cregit-Linux how code gets into the kernel

Release 4.14 drivers/iio/adc/ti-adc084s021.c

Directory: drivers/iio/adc
/**
 * Copyright (C) 2017 Axis Communications AB
 *
 * Driver for Texas Instruments' ADC084S021 ADC chip.
 * Datasheets can be found here:
 * http://www.ti.com/lit/ds/symlink/adc084s021.pdf
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/regulator/consumer.h>


#define ADC084S021_DRIVER_NAME "adc084s021"


struct adc084s021 {
	
struct spi_device *spi;
	
struct spi_message message;
	
struct spi_transfer spi_trans;
	
struct regulator *reg;
	
struct mutex lock;
	/*
         * DMA (thus cache coherency maintenance) requires the
         * transfer buffers to live in their own cache line.
         */
	
u16 tx_buf[4] ____cacheline_aligned;
	
__be16 rx_buf[5]; /* First 16-bits are trash */
};


#define ADC084S021_VOLTAGE_CHANNEL(num)                  \
	{                                                      \
                .type = IIO_VOLTAGE,                                 \
                .channel = (num),                                    \
                .indexed = 1,                                        \
                .scan_index = (num),                                 \
                .scan_type = {                                       \
                        .sign = 'u',                                       \
                        .realbits = 8,                                     \
                        .storagebits = 16,                                 \
                        .shift = 4,                                        \
                        .endianness = IIO_BE,                              \
                },                                                   \
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),        \
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
        }


static const struct iio_chan_spec adc084s021_channels[] = {
	ADC084S021_VOLTAGE_CHANNEL(0),
	ADC084S021_VOLTAGE_CHANNEL(1),
	ADC084S021_VOLTAGE_CHANNEL(2),
	ADC084S021_VOLTAGE_CHANNEL(3),
	IIO_CHAN_SOFT_TIMESTAMP(4),
};

/**
 * Read an ADC channel and return its value.
 *
 * @adc: The ADC SPI data.
 * @data: Buffer for converted data.
 */

static int adc084s021_adc_conversion(struct adc084s021 *adc, void *data) { int n_words = (adc->spi_trans.len >> 1) - 1; /* Discard first word */ int ret, i = 0; u16 *p = data; /* Do the transfer */ ret = spi_sync(adc->spi, &adc->message); if (ret < 0) return ret; for (; i < n_words; i++) *(p + i) = adc->rx_buf[i + 1]; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Mårten Lindahl97100.00%1100.00%
Total97100.00%1100.00%


static int adc084s021_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, int *val2, long mask) { struct adc084s021 *adc = iio_priv(indio_dev); int ret; switch (mask) { case IIO_CHAN_INFO_RAW: ret = iio_device_claim_direct_mode(indio_dev); if (ret < 0) return ret; ret = regulator_enable(adc->reg); if (ret) { iio_device_release_direct_mode(indio_dev); return ret; } adc->tx_buf[0] = channel->channel << 3; ret = adc084s021_adc_conversion(adc, val); iio_device_release_direct_mode(indio_dev); regulator_disable(adc->reg); if (ret < 0) return ret; *val = be16_to_cpu(*val); *val = (*val >> channel->scan_type.shift) & 0xff; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: ret = regulator_enable(adc->reg); if (ret) return ret; ret = regulator_get_voltage(adc->reg); regulator_disable(adc->reg); if (ret < 0) return ret; *val = ret / 1000; return IIO_VAL_INT; default: return -EINVAL; } }

Contributors

PersonTokensPropCommitsCommitProp
Mårten Lindahl219100.00%1100.00%
Total219100.00%1100.00%

/** * Read enabled ADC channels and push data to the buffer. * * @irq: The interrupt number (not used). * @pollfunc: Pointer to the poll func. */
static irqreturn_t adc084s021_buffer_trigger_handler(int irq, void *pollfunc) { struct iio_poll_func *pf = pollfunc; struct iio_dev *indio_dev = pf->indio_dev; struct adc084s021 *adc = iio_priv(indio_dev); __be16 data[8] = {0}; /* 4 * 16-bit words of data + 8 bytes timestamp */ mutex_lock(&adc->lock); if (adc084s021_adc_conversion(adc, &data) < 0) dev_err(&adc->spi->dev, "Failed to read data\n"); iio_push_to_buffers_with_timestamp(indio_dev, data, iio_get_time_ns(indio_dev)); mutex_unlock(&adc->lock); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Mårten Lindahl112100.00%1100.00%
Total112100.00%1100.00%


static int adc084s021_buffer_preenable(struct iio_dev *indio_dev) { struct adc084s021 *adc = iio_priv(indio_dev); int scan_index; int i = 0; for_each_set_bit(scan_index, indio_dev->active_scan_mask, indio_dev->masklength) { const struct iio_chan_spec *channel = &indio_dev->channels[scan_index]; adc->tx_buf[i++] = channel->channel << 3; } adc->spi_trans.len = 2 + (i * sizeof(__be16)); /* Trash + channels */ return regulator_enable(adc->reg); }

Contributors

PersonTokensPropCommitsCommitProp
Mårten Lindahl93100.00%1100.00%
Total93100.00%1100.00%


static int adc084s021_buffer_postdisable(struct iio_dev *indio_dev) { struct adc084s021 *adc = iio_priv(indio_dev); adc->spi_trans.len = 4; /* Trash + single channel */ return regulator_disable(adc->reg); }

Contributors

PersonTokensPropCommitsCommitProp
Mårten Lindahl38100.00%1100.00%
Total38100.00%1100.00%

static const struct iio_info adc084s021_info = { .read_raw = adc084s021_read_raw, .driver_module = THIS_MODULE, }; static const struct iio_buffer_setup_ops adc084s021_buffer_setup_ops = { .preenable = adc084s021_buffer_preenable, .postenable = iio_triggered_buffer_postenable, .predisable = iio_triggered_buffer_predisable, .postdisable = adc084s021_buffer_postdisable, };
static int adc084s021_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct adc084s021 *adc; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); if (!indio_dev) { dev_err(&spi->dev, "Failed to allocate IIO device\n"); return -ENOMEM; } adc = iio_priv(indio_dev); adc->spi = spi; /* Connect the SPI device and the iio dev */ spi_set_drvdata(spi, indio_dev); /* Initiate the Industrial I/O device */ indio_dev->dev.parent = &spi->dev; indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &adc084s021_info; indio_dev->channels = adc084s021_channels; indio_dev->num_channels = ARRAY_SIZE(adc084s021_channels); /* Create SPI transfer for channel reads */ adc->spi_trans.tx_buf = adc->tx_buf; adc->spi_trans.rx_buf = adc->rx_buf; adc->spi_trans.len = 4; /* Trash + single channel */ spi_message_init_with_transfers(&adc->message, &adc->spi_trans, 1); adc->reg = devm_regulator_get(&spi->dev, "vref"); if (IS_ERR(adc->reg)) return PTR_ERR(adc->reg); mutex_init(&adc->lock); /* Setup triggered buffer with pollfunction */ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, adc084s021_buffer_trigger_handler, &adc084s021_buffer_setup_ops); if (ret) { dev_err(&spi->dev, "Failed to setup triggered buffer\n"); return ret; } return devm_iio_device_register(&spi->dev, indio_dev); }

Contributors

PersonTokensPropCommitsCommitProp
Mårten Lindahl279100.00%1100.00%
Total279100.00%1100.00%

static const struct of_device_id adc084s021_of_match[] = { { .compatible = "ti,adc084s021", }, {}, }; MODULE_DEVICE_TABLE(of, adc084s021_of_match); static const struct spi_device_id adc084s021_id[] = { { ADC084S021_DRIVER_NAME, 0}, {} }; MODULE_DEVICE_TABLE(spi, adc084s021_id); static struct spi_driver adc084s021_driver = { .driver = { .name = ADC084S021_DRIVER_NAME, .of_match_table = of_match_ptr(adc084s021_of_match), }, .probe = adc084s021_probe, .id_table = adc084s021_id, }; module_spi_driver(adc084s021_driver); MODULE_AUTHOR("MÃ¥rten Lindahl <martenli@axis.com>"); MODULE_DESCRIPTION("Texas Instruments ADC084S021"); MODULE_LICENSE("GPL v2"); MODULE_VERSION("1.0");

Overall Contributors

PersonTokensPropCommitsCommitProp
Mårten Lindahl1111100.00%1100.00%
Total1111100.00%1100.00%
Directory: drivers/iio/adc
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.