Commit d9750a2f authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-4.6b' of...

Merge tag 'iio-for-4.6b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

2nd round of new IIO device support, features and cleanups for the 4.6 cycle.

New Device Support
* Apex stx104 DAC
  - new driver for this PC104 board. Right now DAC support only.
* ADI ad5064
  - Add support for ad5625, ad5627, ad5645, ad5665, ad5667 DACs.
  - Add support for Linear Technology ltc2606, ltc2607, ltc2609, ltc2616,
    ltc2617, ltc2619, ltc2626, ltc2627 and ltc2629.
* ADI ad7192
  - add support for the ad7193
* Invensense mpu6050
  - substantial rework of driver to use regmap allowing SPI support extending
    the now split driver to cover the MPU6000.
* TI adc0832
  - new driver supporting ADC0831, ADC0832, ADC0834 and ADC0838 ADCs.
* TI ads1015
  - new driver, note that there is an existing hwmon driver. The long term
    intention is to probably remove the hwmon driver but for now we just have
    guards in place to ensure this driver is not built if that one is enabled.
* TI afe4403
  - new driver for this heart rate monitor / pulse oximeter front end chip.
* TI afe4404
  - new driver for this heart rate monitor / pulse oximeter front end chip.

Staging Graduations
* mxs-lradc
  - A combined general purpose and touch screen (input) device driver.
    Originally held in staging to allow reworking into and MFD but as
    that wasn't happening and isn't an absolute requirement we are moving
    it out of staging.

Driver new features
* ms5611
  - triggered buffer support
  - IIO_CHAN_INFO_SCALE to aid the triggered buffer support.

Driver cleanups / reworks / fixes
* ad5064
  - Use an enum for the register map layout to allow support of additional
    chips (precursor to the new support listed above).
  - Structural driver changes to allow support of the slightly different
    handling for the ltc parts above.
* ad5933
  - drop an exceptional & unnecessary for a function pointer.
* ad7606
  - Cleanup the repeated copies of pm ops.
  - consolidate the various channels specs via a sport of rearranging so only
    one version is needed.
* atlas ph sensor
  - add select IRQ_WORK
* hmc8543 (soon to move out of staging)
  - Comment style fixes
  - functionality of suspend and resume was swapped.
* spear-adc
  - use devm_clk_dev instead of managing the clk lifetime by hand.

Core
* Use new dmaengine_terminate_sync call to avoid a theoretical race.
* Fix docs for mlock in struct iio_dev as it is correctly taken in some
  drivers (docs used to say for core only).
* Add a helper function for calculating the scan index storage size within
  the core cutting out some cut and paste versions of the same code.
parents 2cdb82c7 ecc24e72
...@@ -496,6 +496,7 @@ Description: ...@@ -496,6 +496,7 @@ Description:
1kohm_to_gnd: connected to ground via an 1kOhm resistor, 1kohm_to_gnd: connected to ground via an 1kOhm resistor,
6kohm_to_gnd: connected to ground via a 6kOhm resistor, 6kohm_to_gnd: connected to ground via a 6kOhm resistor,
20kohm_to_gnd: connected to ground via a 20kOhm resistor, 20kohm_to_gnd: connected to ground via a 20kOhm resistor,
90kohm_to_gnd: connected to ground via a 90kOhm resistor,
100kohm_to_gnd: connected to ground via an 100kOhm resistor, 100kohm_to_gnd: connected to ground via an 100kOhm resistor,
125kohm_to_gnd: connected to ground via an 125kOhm resistor, 125kohm_to_gnd: connected to ground via an 125kOhm resistor,
500kohm_to_gnd: connected to ground via a 500kOhm resistor, 500kohm_to_gnd: connected to ground via a 500kOhm resistor,
......
What: /sys/bus/iio/devices/iio:deviceX/tia_resistanceY
/sys/bus/iio/devices/iio:deviceX/tia_capacitanceY
Date: December 2015
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get and set the resistance and the capacitance settings for the
Transimpedance Amplifier. Y is 1 for Rf1 and Cf1, Y is 2 for
Rf2 and Cf2 values.
What: /sys/bus/iio/devices/iio:deviceX/tia_separate_en
Date: December 2015
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Enable or disable separate settings for the TransImpedance
Amplifier above, when disabled both values are set by the
first channel.
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ledY_raw
/sys/bus/iio/devices/iio:deviceX/in_intensity_ledY_ambient_raw
Date: December 2015
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get measured values from the ADC for these stages. Y is the
specific LED number. The values are expressed in 24-bit twos
complement.
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ledY-ledY_ambient_raw
Date: December 2015
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get differential values from the ADC for these stages. Y is the
specific LED number. The values are expressed in 24-bit twos
complement for the specified LEDs.
What: /sys/bus/iio/devices/iio:deviceX/out_current_ledY_offset
/sys/bus/iio/devices/iio:deviceX/out_current_ledY_ambient_offset
Date: December 2015
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get and set the offset cancellation DAC setting for these
stages. The values are expressed in 5-bit sign-magnitude.
What: /sys/bus/iio/devices/iio:deviceX/out_current_ledY_raw
Date: December 2015
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get and set the LED current for the specified LED. Y is the
specific LED number.
* Texas Instruments' ADC0831/ADC0832/ADC0832/ADC0838
Required properties:
- compatible: Should be one of
* "ti,adc0831"
* "ti,adc0832"
* "ti,adc0834"
* "ti,adc0838"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
- spi-max-frequency: Max SPI frequency to use (< 400000)
Example:
adc@0 {
compatible = "ti,adc0832";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <200000>;
};
Texas Instruments AFE4403 Heart rate and Pulse Oximeter
Required properties:
- compatible : Should be "ti,afe4403".
- reg : SPI chip select address of device.
- tx-supply : Regulator supply to transmitting LEDs.
- interrupt-parent : Phandle to he parent interrupt controller.
- interrupts : The interrupt line the device ADC_RDY pin is
connected to. For details refer to,
../../interrupt-controller/interrupts.txt.
Optional properties:
- reset-gpios : GPIO used to reset the device.
For details refer to, ../../gpio/gpio.txt.
For other required and optional properties of SPI slave nodes
please refer to ../../spi/spi-bus.txt.
Example:
&spi0 {
heart_mon@0 {
compatible = "ti,afe4403";
reg = <0>;
spi-max-frequency = <10000000>;
tx-supply = <&vbat>;
interrupt-parent = <&gpio1>;
interrupts = <28 IRQ_TYPE_EDGE_RISING>;
reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
};
};
Texas Instruments AFE4404 Heart rate and Pulse Oximeter
Required properties:
- compatible : Should be "ti,afe4404".
- reg : I2C address of the device.
- tx-supply : Regulator supply to transmitting LEDs.
- interrupt-parent : Phandle to he parent interrupt controller.
- interrupts : The interrupt line the device ADC_RDY pin is
connected to. For details refer to,
../interrupt-controller/interrupts.txt.
Optional properties:
- reset-gpios : GPIO used to reset the device.
For details refer to, ../gpio/gpio.txt.
Example:
&i2c2 {
heart_mon@58 {
compatible = "ti,afe4404";
reg = <0x58>;
tx-supply = <&vbat>;
interrupt-parent = <&gpio1>;
interrupts = <28 IRQ_TYPE_EDGE_RISING>;
reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
};
};
...@@ -769,6 +769,12 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) ...@@ -769,6 +769,12 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: sound/aoa/ F: sound/aoa/
APEX EMBEDDED SYSTEMS STX104 DAC DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/dac/stx104.c
APM DRIVER APM DRIVER
M: Jiri Kosina <jikos@kernel.org> M: Jiri Kosina <jikos@kernel.org>
S: Odd fixes S: Odd fixes
......
...@@ -297,6 +297,20 @@ config MEN_Z188_ADC ...@@ -297,6 +297,20 @@ config MEN_Z188_ADC
This driver can also be built as a module. If so, the module will be This driver can also be built as a module. If so, the module will be
called men_z188_adc. called men_z188_adc.
config MXS_LRADC
tristate "Freescale i.MX23/i.MX28 LRADC"
depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
depends on INPUT
select STMP_DEVICE
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for i.MX23/i.MX28 LRADC convertor
built into these chips.
To compile this driver as a module, choose M here: the
module will be called mxs-lradc.
config NAU7802 config NAU7802
tristate "Nuvoton NAU7802 ADC driver" tristate "Nuvoton NAU7802 ADC driver"
depends on I2C depends on I2C
...@@ -362,6 +376,16 @@ config TI_ADC081C ...@@ -362,6 +376,16 @@ config TI_ADC081C
This driver can also be built as a module. If so, the module will be This driver can also be built as a module. If so, the module will be
called ti-adc081c. called ti-adc081c.
config TI_ADC0832
tristate "Texas Instruments ADC0831/ADC0832/ADC0834/ADC0838"
depends on SPI
help
If you say yes here you get support for Texas Instruments ADC0831,
ADC0832, ADC0834, ADC0838 ADC chips.
This driver can also be built as a module. If so, the module will be
called ti-adc0832.
config TI_ADC128S052 config TI_ADC128S052
tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021" tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
depends on SPI depends on SPI
...@@ -372,6 +396,19 @@ config TI_ADC128S052 ...@@ -372,6 +396,19 @@ config TI_ADC128S052
This driver can also be built as a module. If so, the module will be This driver can also be built as a module. If so, the module will be
called ti-adc128s052. called ti-adc128s052.
config TI_ADS1015
tristate "Texas Instruments ADS1015 ADC"
depends on I2C && !SENSORS_ADS1015
select REGMAP_I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for Texas Instruments ADS1015
ADC chip.
This driver can also be built as a module. If so, the module will be
called ti-ads1015.
config TI_ADS8688 config TI_ADS8688
tristate "Texas Instruments ADS8688" tristate "Texas Instruments ADS8688"
depends on SPI && OF depends on SPI && OF
......
...@@ -29,13 +29,16 @@ obj-$(CONFIG_MAX1363) += max1363.o ...@@ -29,13 +29,16 @@ obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
......
...@@ -443,7 +443,8 @@ static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch) ...@@ -443,7 +443,8 @@ static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
LRADC_CH_NUM_SAMPLES(lradc->over_sample_cnt - 1), LRADC_CH_NUM_SAMPLES(lradc->over_sample_cnt - 1),
LRADC_CH(ch)); LRADC_CH(ch));
/* from the datasheet: /*
* from the datasheet:
* "Software must clear this register in preparation for a * "Software must clear this register in preparation for a
* multi-cycle accumulation. * multi-cycle accumulation.
*/ */
...@@ -504,7 +505,8 @@ static void mxs_lradc_setup_ts_pressure(struct mxs_lradc *lradc, unsigned ch1, ...@@ -504,7 +505,8 @@ static void mxs_lradc_setup_ts_pressure(struct mxs_lradc *lradc, unsigned ch1,
mxs_lradc_reg_wrt(lradc, reg, LRADC_CH(ch1)); mxs_lradc_reg_wrt(lradc, reg, LRADC_CH(ch1));
mxs_lradc_reg_wrt(lradc, reg, LRADC_CH(ch2)); mxs_lradc_reg_wrt(lradc, reg, LRADC_CH(ch2));
/* from the datasheet: /*
* from the datasheet:
* "Software must clear this register in preparation for a * "Software must clear this register in preparation for a
* multi-cycle accumulation. * multi-cycle accumulation.
*/ */
...@@ -914,7 +916,8 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, ...@@ -914,7 +916,8 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev,
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_TEMP) { if (chan->type == IIO_TEMP) {
/* From the datasheet, we have to multiply by 1.012 and /*
* From the datasheet, we have to multiply by 1.012 and
* divide by 4 * divide by 4
*/ */
*val = 0; *val = 0;
...@@ -929,7 +932,8 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, ...@@ -929,7 +932,8 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev,
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
if (chan->type == IIO_TEMP) { if (chan->type == IIO_TEMP) {
/* The calculated value from the ADC is in Kelvin, we /*
* The calculated value from the ADC is in Kelvin, we
* want Celsius for hwmon so the offset is -273.15 * want Celsius for hwmon so the offset is -273.15
* The offset is applied before scaling so it is * The offset is applied before scaling so it is
* actually -213.15 * 4 / 1.012 = -1079.644268 * actually -213.15 * 4 / 1.012 = -1079.644268
...@@ -1750,6 +1754,7 @@ static int mxs_lradc_remove(struct platform_device *pdev) ...@@ -1750,6 +1754,7 @@ static int mxs_lradc_remove(struct platform_device *pdev)
iio_triggered_buffer_cleanup(iio); iio_triggered_buffer_cleanup(iio);
clk_disable_unprepare(lradc->clk); clk_disable_unprepare(lradc->clk);
return 0; return 0;
} }
......
/*
* ADC0831/ADC0832/ADC0834/ADC0838 8-bit ADC driver
*
* Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* Datasheet: http://www.ti.com/lit/ds/symlink/adc0832-n.pdf
*/
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
enum {
adc0831,
adc0832,
adc0834,
adc0838,
};
struct adc0832 {
struct spi_device *spi;
struct regulator *reg;
struct mutex lock;
u8 mux_bits;
u8 tx_buf[2] ____cacheline_aligned;
u8 rx_buf[2];
};
#define ADC0832_VOLTAGE_CHANNEL(chan) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
#define ADC0832_VOLTAGE_CHANNEL_DIFF(chan1, chan2) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (chan1), \
.channel2 = (chan2), \
.differential = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
static const struct iio_chan_spec adc0831_channels[] = {
ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1),
};
static const struct iio_chan_spec adc0832_channels[] = {
ADC0832_VOLTAGE_CHANNEL(0),
ADC0832_VOLTAGE_CHANNEL(1),
ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1),
ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0),
};
static const struct iio_chan_spec adc0834_channels[] = {
ADC0832_VOLTAGE_CHANNEL(0),
ADC0832_VOLTAGE_CHANNEL(1),
ADC0832_VOLTAGE_CHANNEL(2),
ADC0832_VOLTAGE_CHANNEL(3),
ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1),
ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0),
ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3),
ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2),
};
static const struct iio_chan_spec adc0838_channels[] = {
ADC0832_VOLTAGE_CHANNEL(0),
ADC0832_VOLTAGE_CHANNEL(1),
ADC0832_VOLTAGE_CHANNEL(2),
ADC0832_VOLTAGE_CHANNEL(3),
ADC0832_VOLTAGE_CHANNEL(4),
ADC0832_VOLTAGE_CHANNEL(5),
ADC0832_VOLTAGE_CHANNEL(6),
ADC0832_VOLTAGE_CHANNEL(7),
ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1),
ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0),
ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3),
ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2),
ADC0832_VOLTAGE_CHANNEL_DIFF(4, 5),
ADC0832_VOLTAGE_CHANNEL_DIFF(5, 4),
ADC0832_VOLTAGE_CHANNEL_DIFF(6, 7),
ADC0832_VOLTAGE_CHANNEL_DIFF(7, 6),
};
static int adc0831_adc_conversion(struct adc0832 *adc)
{
struct spi_device *spi = adc->spi;
int ret;
ret = spi_read(spi, &adc->rx_buf, 2);
if (ret)
return ret;
/*
* Skip TRI-STATE and a leading zero
*/
return (adc->rx_buf[0] << 2 & 0xff) | (adc->rx_buf[1] >> 6);
}
static int adc0832_adc_conversion(struct adc0832 *adc, int channel,
bool differential)
{
struct spi_device *spi = adc->spi;
struct spi_transfer xfer = {
.tx_buf = adc->tx_buf,
.rx_buf = adc->rx_buf,
.len = 2,
};
int ret;
if (!adc->mux_bits)
return adc0831_adc_conversion(adc);
/* start bit */
adc->tx_buf[0] = 1 << (adc->mux_bits + 1);
/* single-ended or differential */
adc->tx_buf[0] |= differential ? 0 : (1 << adc->mux_bits);
/* odd / sign */
adc->tx_buf[0] |= (channel % 2) << (adc->mux_bits - 1);
/* select */
if (adc->mux_bits > 1)
adc->tx_buf[0] |= channel / 2;
/* align Data output BIT7 (MSB) to 8-bit boundary */
adc->tx_buf[0] <<= 1;
ret = spi_sync_transfer(spi, &xfer, 1);
if (ret)
return ret;
return adc->rx_buf[1];
}
static int adc0832_read_raw(struct iio_dev *iio,
struct iio_chan_spec const *channel, int *value,
int *shift, long mask)
{
struct adc0832 *adc = iio_priv(iio);
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&adc->lock);
*value = adc0832_adc_conversion(adc, channel->channel,
channel->differential);
mutex_unlock(&adc->lock);
if (*value < 0)
return *value;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*value = regulator_get_voltage(adc->reg);
if (*value < 0)
return *value;
/* convert regulator output voltage to mV */
*value /= 1000;
*shift = 8;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const struct iio_info adc0832_info = {
.read_raw = adc0832_read_raw,
.driver_module = THIS_MODULE,
};
static int adc0832_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adc0832 *adc;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
mutex_init(&adc->lock);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adc0832_info;
indio_dev->modes = INDIO_DIRECT_MODE;
switch (spi_get_device_id(spi)->driver_data) {
case adc0831:
adc->mux_bits = 0;
indio_dev->channels = adc0831_channels;
indio_dev->num_channels = ARRAY_SIZE(adc0831_channels);
break;
case adc0832:
adc->mux_bits = 1;
indio_dev->channels = adc0832_channels;
indio_dev->num_channels = ARRAY_SIZE(adc0832_channels);
break;
case adc0834:
adc->mux_bits = 2;
indio_dev->channels = adc0834_channels;
indio_dev->num_channels = ARRAY_SIZE(adc0834_channels);
break;
case adc0838:
adc->mux_bits = 3;
indio_dev->channels = adc0838_channels;
indio_dev->num_channels = ARRAY_SIZE(adc0838_channels);
break;
default:
return -EINVAL;
}
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
return PTR_ERR(adc->reg);
ret = regulator_enable(adc->reg);
if (ret)
return ret;
spi_set_drvdata(spi, indio_dev);
ret = iio_device_register(indio_dev);
if (ret)
regulator_disable(adc->reg);
return ret;
}
static int adc0832_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adc0832 *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(adc->reg);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id adc0832_dt_ids[] = {
{ .compatible = "ti,adc0831", },
{ .compatible = "ti,adc0832", },
{ .compatible = "ti,adc0834", },
{ .compatible = "ti,adc0838", },
{}
};
MODULE_DEVICE_TABLE(of, adc0832_dt_ids);
#endif
static const struct spi_device_id adc0832_id[] = {
{ "adc0831", adc0831 },
{ "adc0832", adc0832 },
{ "adc0834", adc0834 },
{ "adc0838", adc0838 },
{}
};
MODULE_DEVICE_TABLE(spi, adc0832_id);
static struct spi_driver adc0832_driver = {
.driver = {
.name = "adc0832",
.of_match_table = of_match_ptr(adc0832_dt_ids),
},
.probe = adc0832_probe,
.remove = adc0832_remove,
.id_table = adc0832_id,
};
module_spi_driver(adc0832_driver);
MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
MODULE_DESCRIPTION("ADC0831/ADC0832/ADC0834/ADC0838 driver");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
...@@ -93,12 +93,7 @@ static void iio_dmaengine_buffer_abort(struct iio_dma_buffer_queue *queue) ...@@ -93,12 +93,7 @@ static void iio_dmaengine_buffer_abort(struct iio_dma_buffer_queue *queue)
struct dmaengine_buffer *dmaengine_buffer = struct dmaengine_buffer *dmaengine_buffer =
iio_buffer_to_dmaengine_buffer(&queue->buffer); iio_buffer_to_dmaengine_buffer(&queue->buffer);
dmaengine_terminate_all(dmaengine_buffer->chan); dmaengine_terminate_sync(dmaengine_buffer->chan);
/* FIXME: There is a slight chance of a race condition here.
* dmaengine_terminate_all() does not guarantee that all transfer
* callbacks have finished running. Need to introduce a
* dmaengine_terminate_all_sync().
*/
iio_dma_buffer_block_list_abort(queue, &dmaengine_buffer->active); iio_dma_buffer_block_list_abort(queue, &dmaengine_buffer->active);
} }
......
...@@ -10,6 +10,7 @@ config ATLAS_PH_SENSOR ...@@ -10,6 +10,7 @@ config ATLAS_PH_SENSOR
select REGMAP_I2C select REGMAP_I2C
select IIO_BUFFER select IIO_BUFFER
select IIO_TRIGGERED_BUFFER select IIO_TRIGGERED_BUFFER
select IRQ_WORK
help help
Say Y here to build I2C interface support for the Atlas Say Y here to build I2C interface support for the Atlas
Scientific OEM pH-SM sensor. Scientific OEM pH-SM sensor.
......
...@@ -10,8 +10,10 @@ config AD5064 ...@@ -10,8 +10,10 @@ config AD5064
depends on (SPI_MASTER && I2C!=m) || I2C depends on (SPI_MASTER && I2C!=m) || I2C
help help
Say yes here to build support for Analog Devices AD5024, AD5025, AD5044, Say yes here to build support for Analog Devices AD5024, AD5025, AD5044,
AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5629R, AD5648, AD5666, AD5668, AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, AD5627, AD5627R,
AD5669R Digital to Analog Converter. AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, AD5666,
AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616,
LTC2617, LTC2619, LTC2626, LTC2627, LTC2629 Digital to Analog Converter.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ad5064. module will be called ad5064.
...@@ -206,4 +208,13 @@ config MCP4922 ...@@ -206,4 +208,13 @@ config MCP4922
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called mcp4922. will be called mcp4922.
config STX104
tristate "Apex Embedded Systems STX104 DAC driver"
depends on ISA
help
Say yes here to build support for the 2-channel DAC on the Apex
Embedded Systems STX104 integrated analog PC/104 card. The base port
addresses for the devices may be configured via the "base" module
parameter array.
endmenu endmenu
...@@ -22,3 +22,4 @@ obj-$(CONFIG_MAX517) += max517.o ...@@ -22,3 +22,4 @@ obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MAX5821) += max5821.o obj-$(CONFIG_MAX5821) += max5821.o
obj-$(CONFIG_MCP4725) += mcp4725.o obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4922) += mcp4922.o obj-$(CONFIG_MCP4922) += mcp4922.o
obj-$(CONFIG_STX104) += stx104.o
This diff is collapsed.
/*
* DAC driver for the Apex Embedded Systems STX104
* Copyright (C) 2016 William Breathitt Gray
*
* 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.
*
* 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 GNU
* General Public License for more details.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#define STX104_NUM_CHAN 2
#define STX104_CHAN(chan) { \
.type = IIO_VOLTAGE, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.indexed = 1, \
.output = 1 \
}
#define STX104_EXTENT 16
/**
* The highest base address possible for an ISA device is 0x3FF; this results in
* 1024 possible base addresses. Dividing the number of possible base addresses
* by the address extent taken by each device results in the maximum number of
* devices on a system.
*/
#define MAX_NUM_STX104 (1024 / STX104_EXTENT)
static unsigned base[MAX_NUM_STX104];
static unsigned num_stx104;
module_param_array(base, uint, &num_stx104, 0);
MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
/**
* struct stx104_iio - IIO device private data structure
* @chan_out_states: channels' output states
* @base: base port address of the IIO device
*/
struct stx104_iio {
unsigned chan_out_states[STX104_NUM_CHAN];
unsigned base;
};
static int stx104_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
struct stx104_iio *const priv = iio_priv(indio_dev);
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
*val = priv->chan_out_states[chan->channel];
return IIO_VAL_INT;
}
static int stx104_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct stx104_iio *const priv = iio_priv(indio_dev);
const unsigned chan_addr_offset = 2 * chan->channel;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
priv->chan_out_states[chan->channel] = val;
outw(val, priv->base + 4 + chan_addr_offset);
return 0;
}
static const struct iio_info stx104_info = {
.driver_module = THIS_MODULE,
.read_raw = stx104_read_raw,
.write_raw = stx104_write_raw
};
static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = {
STX104_CHAN(0),
STX104_CHAN(1)
};
static int stx104_probe(struct device *dev, unsigned int id)
{
struct iio_dev *indio_dev;
struct stx104_iio *priv;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
if (!devm_request_region(dev, base[id], STX104_EXTENT,
dev_name(dev))) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
base[id], base[id] + STX104_EXTENT);
return -EBUSY;
}
indio_dev->info = &stx104_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = stx104_channels;
indio_dev->num_channels = STX104_NUM_CHAN;
indio_dev->name = dev_name(dev);
priv = iio_priv(indio_dev);
priv->base = base[id];
/* initialize DAC output to 0V */
outw(0, base[id] + 4);
outw(0, base[id] + 6);
return devm_iio_device_register(dev, indio_dev);
}
static struct isa_driver stx104_driver = {
.probe = stx104_probe,
.driver = {
.name = "stx104"
}
};
static void __exit stx104_exit(void)
{
isa_unregister_driver(&stx104_driver);
}
static int __init stx104_init(void)
{
return isa_register_driver(&stx104_driver, num_stx104);
}
module_init(stx104_init);
module_exit(stx104_exit);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("Apex Embedded Systems STX104 DAC driver");
MODULE_LICENSE("GPL v2");
...@@ -3,7 +3,34 @@ ...@@ -3,7 +3,34 @@
# #
# When adding new entries keep the list in alphabetical order # When adding new entries keep the list in alphabetical order
menu "Health sensors" menu "Health Sensors"
menu "Heart Rate Monitors"
config AFE4403
tristate "TI AFE4403 Heart Rate Monitor"
depends on SPI_MASTER
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes to choose the Texas Instruments AFE4403
heart rate monitor and low-cost pulse oximeter.
To compile this driver as a module, choose M here: the
module will be called afe4403.
config AFE4404
tristate "TI AFE4404 heart rate and pulse oximeter sensor"
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes to choose the Texas Instruments AFE4404
heart rate monitor and low-cost pulse oximeter.
To compile this driver as a module, choose M here: the
module will be called afe4404.
config MAX30100 config MAX30100
tristate "MAX30100 heart rate and pulse oximeter sensor" tristate "MAX30100 heart rate and pulse oximeter sensor"
...@@ -19,3 +46,5 @@ config MAX30100 ...@@ -19,3 +46,5 @@ config MAX30100
module will be called max30100. module will be called max30100.
endmenu endmenu
endmenu
...@@ -4,4 +4,6 @@ ...@@ -4,4 +4,6 @@
# When adding new entries keep the list in alphabetical order # When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AFE4403) += afe4403.o
obj-$(CONFIG_AFE4404) += afe4404.o
obj-$(CONFIG_MAX30100) += max30100.o obj-$(CONFIG_MAX30100) += max30100.o
This diff is collapsed.
This diff is collapsed.
/*
* AFE440X Heart Rate Monitors and Low-Cost Pulse Oximeters
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
*
* 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.
*
* 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 GNU
* General Public License for more details.
*/
#ifndef _AFE440X_H
#define _AFE440X_H
/* AFE440X registers */
#define AFE440X_CONTROL0 0x00
#define AFE440X_LED2STC 0x01
#define AFE440X_LED2ENDC 0x02
#define AFE440X_LED1LEDSTC 0x03
#define AFE440X_LED1LEDENDC 0x04
#define AFE440X_ALED2STC 0x05
#define AFE440X_ALED2ENDC 0x06
#define AFE440X_LED1STC 0x07
#define AFE440X_LED1ENDC 0x08
#define AFE440X_LED2LEDSTC 0x09
#define AFE440X_LED2LEDENDC 0x0a
#define AFE440X_ALED1STC 0x0b
#define AFE440X_ALED1ENDC 0x0c
#define AFE440X_LED2CONVST 0x0d
#define AFE440X_LED2CONVEND 0x0e
#define AFE440X_ALED2CONVST 0x0f
#define AFE440X_ALED2CONVEND 0x10
#define AFE440X_LED1CONVST 0x11
#define AFE440X_LED1CONVEND 0x12
#define AFE440X_ALED1CONVST 0x13
#define AFE440X_ALED1CONVEND 0x14
#define AFE440X_ADCRSTSTCT0 0x15
#define AFE440X_ADCRSTENDCT0 0x16
#define AFE440X_ADCRSTSTCT1 0x17
#define AFE440X_ADCRSTENDCT1 0x18
#define AFE440X_ADCRSTSTCT2 0x19
#define AFE440X_ADCRSTENDCT2 0x1a
#define AFE440X_ADCRSTSTCT3 0x1b
#define AFE440X_ADCRSTENDCT3 0x1c
#define AFE440X_PRPCOUNT 0x1d
#define AFE440X_CONTROL1 0x1e
#define AFE440X_LEDCNTRL 0x22
#define AFE440X_CONTROL2 0x23
#define AFE440X_ALARM 0x29
#define AFE440X_LED2VAL 0x2a
#define AFE440X_ALED2VAL 0x2b
#define AFE440X_LED1VAL 0x2c
#define AFE440X_ALED1VAL 0x2d
#define AFE440X_LED2_ALED2VAL 0x2e
#define AFE440X_LED1_ALED1VAL 0x2f
#define AFE440X_CONTROL3 0x31
#define AFE440X_PDNCYCLESTC 0x32
#define AFE440X_PDNCYCLEENDC 0x33
/* CONTROL0 register fields */
#define AFE440X_CONTROL0_REG_READ BIT(0)
#define AFE440X_CONTROL0_TM_COUNT_RST BIT(1)
#define AFE440X_CONTROL0_SW_RESET BIT(3)
/* CONTROL1 register fields */
#define AFE440X_CONTROL1_TIMEREN BIT(8)
/* TIAGAIN register fields */
#define AFE440X_TIAGAIN_ENSEPGAIN_MASK BIT(15)
#define AFE440X_TIAGAIN_ENSEPGAIN_SHIFT 15
/* CONTROL2 register fields */
#define AFE440X_CONTROL2_PDN_AFE BIT(0)
#define AFE440X_CONTROL2_PDN_RX BIT(1)
#define AFE440X_CONTROL2_DYNAMIC4 BIT(3)
#define AFE440X_CONTROL2_DYNAMIC3 BIT(4)
#define AFE440X_CONTROL2_DYNAMIC2 BIT(14)
#define AFE440X_CONTROL2_DYNAMIC1 BIT(20)
/* CONTROL3 register fields */
#define AFE440X_CONTROL3_CLKDIV GENMASK(2, 0)
/* CONTROL0 values */
#define AFE440X_CONTROL0_WRITE 0x0
#define AFE440X_CONTROL0_READ 0x1
struct afe440x_reg_info {
unsigned int reg;
unsigned int offreg;
unsigned int shift;
unsigned int mask;
};
#define AFE440X_REG_INFO(_reg, _offreg, _sm) \
{ \
.reg = _reg, \
.offreg = _offreg, \
.shift = _sm ## _SHIFT, \
.mask = _sm ## _MASK, \
}
#define AFE440X_INTENSITY_CHAN(_index, _name, _mask) \
{ \
.type = IIO_INTENSITY, \
.channel = _index, \
.address = _index, \
.scan_index = _index, \
.scan_type = { \
.sign = 's', \
.realbits = 24, \
.storagebits = 32, \
.endianness = IIO_CPU, \
}, \
.extend_name = _name, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
_mask, \
}
#define AFE440X_CURRENT_CHAN(_index, _name) \
{ \
.type = IIO_CURRENT, \
.channel = _index, \
.address = _index, \
.scan_index = _index, \
.extend_name = _name, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.output = true, \
}
enum afe440x_reg_type {
SIMPLE,
RESISTANCE,
CAPACITANCE,
};
struct afe440x_val_table {
int integer;
int fract;
};
#define AFE440X_TABLE_ATTR(_name, _table) \
static ssize_t _name ## _show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
ssize_t len = 0; \
int i; \
\
for (i = 0; i < ARRAY_SIZE(_table); i++) \
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ", \
_table[i].integer, \
_table[i].fract); \
\
buf[len - 1] = '\n'; \
\
return len; \
} \
static DEVICE_ATTR_RO(_name)
struct afe440x_attr {
struct device_attribute dev_attr;
unsigned int reg;
unsigned int shift;
unsigned int mask;
enum afe440x_reg_type type;
const struct afe440x_val_table *val_table;
unsigned int table_size;
};
#define to_afe440x_attr(_dev_attr) \
container_of(_dev_attr, struct afe440x_attr, dev_attr)
#define AFE440X_ATTR(_name, _reg, _field, _type, _table, _size) \
struct afe440x_attr afe440x_attr_##_name = { \
.dev_attr = __ATTR(_name, (S_IRUGO | S_IWUSR), \
afe440x_show_register, \
afe440x_store_register), \
.reg = _reg, \
.shift = _field ## _SHIFT, \
.mask = _field ## _MASK, \
.type = _type, \
.val_table = _table, \
.table_size = _size, \
}
#endif /* _AFE440X_H */
...@@ -3,15 +3,31 @@ ...@@ -3,15 +3,31 @@
# #
config INV_MPU6050_IIO config INV_MPU6050_IIO
tristate "Invensense MPU6050 devices" tristate
depends on I2C && SYSFS
depends on I2C_MUX
select IIO_BUFFER select IIO_BUFFER
select IIO_TRIGGERED_BUFFER select IIO_TRIGGERED_BUFFER
config INV_MPU6050_I2C
tristate "Invensense MPU6050 devices (I2C)"
depends on I2C
select INV_MPU6050_IIO
select I2C_MUX
select REGMAP_I2C
help help
This driver supports the Invensense MPU6050 devices. This driver supports the Invensense MPU6050 devices.
This driver can also support MPU6500 in MPU6050 compatibility mode This driver can also support MPU6500 in MPU6050 compatibility mode
and also in MPU6500 mode with some limitations. and also in MPU6500 mode with some limitations.
It is a gyroscope/accelerometer combo device. It is a gyroscope/accelerometer combo device.
This driver can be built as a module. The module will be called This driver can be built as a module. The module will be called
inv-mpu6050. inv-mpu6050-i2c.
config INV_MPU6050_SPI
tristate "Invensense MPU6050 devices (SPI)"
depends on SPI_MASTER
select INV_MPU6050_IIO
select REGMAP_SPI
help
This driver supports the Invensense MPU6050 devices.
It is a gyroscope/accelerometer combo device.
This driver can be built as a module. The module will be called
inv-mpu6050-spi.
...@@ -3,4 +3,10 @@ ...@@ -3,4 +3,10 @@
# #
obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o inv_mpu_acpi.o inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
inv-mpu6050-i2c-objs := inv_mpu_i2c.o inv_mpu_acpi.o
obj-$(CONFIG_INV_MPU6050_SPI) += inv-mpu6050-spi.o
inv-mpu6050-spi-objs := inv_mpu_spi.o
...@@ -139,22 +139,23 @@ static int inv_mpu_process_acpi_config(struct i2c_client *client, ...@@ -139,22 +139,23 @@ static int inv_mpu_process_acpi_config(struct i2c_client *client,
return 0; return 0;
} }
int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
{ {
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
st->mux_client = NULL; st->mux_client = NULL;
if (ACPI_HANDLE(&st->client->dev)) { if (ACPI_HANDLE(&client->dev)) {
struct i2c_board_info info; struct i2c_board_info info;
struct acpi_device *adev; struct acpi_device *adev;
int ret = -1; int ret = -1;
adev = ACPI_COMPANION(&st->client->dev); adev = ACPI_COMPANION(&client->dev);
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
dmi_check_system(inv_mpu_dev_list); dmi_check_system(inv_mpu_dev_list);
switch (matched_product_name) { switch (matched_product_name) {
case INV_MPU_ASUS_T100TA: case INV_MPU_ASUS_T100TA:
ret = asus_acpi_get_sensor_info(adev, st->client, ret = asus_acpi_get_sensor_info(adev, client,
&info); &info);
break; break;
/* Add more matched product processing here */ /* Add more matched product processing here */
...@@ -166,7 +167,7 @@ int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) ...@@ -166,7 +167,7 @@ int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st)
/* No matching DMI, so create device on INV6XX type */ /* No matching DMI, so create device on INV6XX type */
unsigned short primary, secondary; unsigned short primary, secondary;
ret = inv_mpu_process_acpi_config(st->client, &primary, ret = inv_mpu_process_acpi_config(client, &primary,
&secondary); &secondary);
if (!ret && secondary) { if (!ret && secondary) {
char *name; char *name;
...@@ -191,8 +192,9 @@ int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) ...@@ -191,8 +192,9 @@ int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st)
return 0; return 0;
} }
void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st) void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
{ {
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
if (st->mux_client) if (st->mux_client)
i2c_unregister_device(st->mux_client); i2c_unregister_device(st->mux_client);
} }
...@@ -200,12 +202,12 @@ void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st) ...@@ -200,12 +202,12 @@ void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st)
#include "inv_mpu_iio.h" #include "inv_mpu_iio.h"
int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
{ {
return 0; return 0;
} }
void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st) void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
{ {
} }
#endif #endif
This diff is collapsed.
/*
* Copyright (C) 2012 Invensense, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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
* GNU General Public License for more details.
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include "inv_mpu_iio.h"
static const struct regmap_config inv_mpu_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
/*
* The i2c read/write needs to happen in unlocked mode. As the parent
* adapter is common. If we use locked versions, it will fail as
* the mux adapter will lock the parent i2c adapter, while calling
* select/deselect functions.
*/
static int inv_mpu6050_write_reg_unlocked(struct i2c_client *client,
u8 reg, u8 d)
{
int ret;
u8 buf[2] = {reg, d};
struct i2c_msg msg[1] = {
{
.addr = client->addr,
.flags = 0,
.len = sizeof(buf),
.buf = buf,
}
};
ret = __i2c_transfer(client->adapter, msg, 1);
if (ret != 1)
return ret;
return 0;
}
static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
u32 chan_id)
{
struct i2c_client *client = mux_priv;
struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
int ret = 0;
/* Use the same mutex which was used everywhere to protect power-op */
mutex_lock(&indio_dev->mlock);
if (!st->powerup_count) {
ret = inv_mpu6050_write_reg_unlocked(client,
st->reg->pwr_mgmt_1, 0);
if (ret)
goto write_error;
msleep(INV_MPU6050_REG_UP_TIME);
}
if (!ret) {
st->powerup_count++;
ret = inv_mpu6050_write_reg_unlocked(client,
st->reg->int_pin_cfg,
INV_MPU6050_INT_PIN_CFG |
INV_MPU6050_BIT_BYPASS_EN);
}
write_error:
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
void *mux_priv, u32 chan_id)
{
struct i2c_client *client = mux_priv;
struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
/* It doesn't really mattter, if any of the calls fails */
inv_mpu6050_write_reg_unlocked(client, st->reg->int_pin_cfg,
INV_MPU6050_INT_PIN_CFG);
st->powerup_count--;
if (!st->powerup_count)
inv_mpu6050_write_reg_unlocked(client, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_SLEEP);
mutex_unlock(&indio_dev->mlock);
return 0;
}
/**
* inv_mpu_probe() - probe function.
* @client: i2c client.
* @id: i2c device id.
*
* Returns 0 on success, a negative error code otherwise.
*/
static int inv_mpu_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct inv_mpu6050_state *st;
int result;
const char *name = id ? id->name : NULL;
struct regmap *regmap;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_I2C_BLOCK))
return -ENOSYS;
regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Failed to register i2c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
result = inv_mpu_core_probe(regmap, client->irq, name, NULL);
if (result < 0)
return result;
st = iio_priv(dev_get_drvdata(&client->dev));
st->mux_adapter = i2c_add_mux_adapter(client->adapter,
&client->dev,
client,
0, 0, 0,
inv_mpu6050_select_bypass,
inv_mpu6050_deselect_bypass);
if (!st->mux_adapter) {
result = -ENODEV;
goto out_unreg_device;
}
result = inv_mpu_acpi_create_mux_client(client);
if (result)
goto out_del_mux;
return 0;
out_del_mux:
i2c_del_mux_adapter(st->mux_adapter);
out_unreg_device:
inv_mpu_core_remove(&client->dev);
return result;
}
static int inv_mpu_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
inv_mpu_acpi_delete_mux_client(client);
i2c_del_mux_adapter(st->mux_adapter);
return inv_mpu_core_remove(&client->dev);
}
/*
* device id table is used to identify what device can be
* supported by this driver
*/
static const struct i2c_device_id inv_mpu_id[] = {
{"mpu6050", INV_MPU6050},
{"mpu6500", INV_MPU6500},
{}
};
MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
static const struct acpi_device_id inv_acpi_match[] = {
{"INVN6500", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
static struct i2c_driver inv_mpu_driver = {
.probe = inv_mpu_probe,
.remove = inv_mpu_remove,
.id_table = inv_mpu_id,
.driver = {
.acpi_match_table = ACPI_PTR(inv_acpi_match),
.name = "inv-mpu6050-i2c",
.pm = &inv_mpu_pmops,
},
};
module_i2c_driver(inv_mpu_driver);
MODULE_AUTHOR("Invensense Corporation");
MODULE_DESCRIPTION("Invensense device MPU6050 driver");
MODULE_LICENSE("GPL");
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/buffer.h> #include <linux/iio/buffer.h>
#include <linux/regmap.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/iio/kfifo_buf.h> #include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger.h> #include <linux/iio/trigger.h>
...@@ -61,6 +62,7 @@ struct inv_mpu6050_reg_map { ...@@ -61,6 +62,7 @@ struct inv_mpu6050_reg_map {
enum inv_devices { enum inv_devices {
INV_MPU6050, INV_MPU6050,
INV_MPU6500, INV_MPU6500,
INV_MPU6000,
INV_NUM_PARTS INV_NUM_PARTS
}; };
...@@ -107,9 +109,10 @@ struct inv_mpu6050_hw { ...@@ -107,9 +109,10 @@ struct inv_mpu6050_hw {
* @hw: Other hardware-specific information. * @hw: Other hardware-specific information.
* @chip_type: chip type. * @chip_type: chip type.
* @time_stamp_lock: spin lock to time stamp. * @time_stamp_lock: spin lock to time stamp.
* @client: i2c client handle.
* @plat_data: platform data. * @plat_data: platform data.
* @timestamps: kfifo queue to store time stamp. * @timestamps: kfifo queue to store time stamp.
* @map regmap pointer.
* @irq interrupt number.
*/ */
struct inv_mpu6050_state { struct inv_mpu6050_state {
#define TIMESTAMP_FIFO_SIZE 16 #define TIMESTAMP_FIFO_SIZE 16
...@@ -119,12 +122,13 @@ struct inv_mpu6050_state { ...@@ -119,12 +122,13 @@ struct inv_mpu6050_state {
const struct inv_mpu6050_hw *hw; const struct inv_mpu6050_hw *hw;
enum inv_devices chip_type; enum inv_devices chip_type;
spinlock_t time_stamp_lock; spinlock_t time_stamp_lock;
struct i2c_client *client;
struct i2c_adapter *mux_adapter; struct i2c_adapter *mux_adapter;
struct i2c_client *mux_client; struct i2c_client *mux_client;
unsigned int powerup_count; unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data; struct inv_mpu6050_platform_data plat_data;
DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
struct regmap *map;
int irq;
}; };
/*register and associated bit definition*/ /*register and associated bit definition*/
...@@ -151,6 +155,7 @@ struct inv_mpu6050_state { ...@@ -151,6 +155,7 @@ struct inv_mpu6050_state {
#define INV_MPU6050_BIT_I2C_MST_EN 0x20 #define INV_MPU6050_BIT_I2C_MST_EN 0x20
#define INV_MPU6050_BIT_FIFO_EN 0x40 #define INV_MPU6050_BIT_FIFO_EN 0x40
#define INV_MPU6050_BIT_DMP_EN 0x80 #define INV_MPU6050_BIT_DMP_EN 0x80
#define INV_MPU6050_BIT_I2C_IF_DIS 0x10
#define INV_MPU6050_REG_PWR_MGMT_1 0x6B #define INV_MPU6050_REG_PWR_MGMT_1 0x6B
#define INV_MPU6050_BIT_H_RESET 0x80 #define INV_MPU6050_BIT_H_RESET 0x80
...@@ -185,6 +190,7 @@ struct inv_mpu6050_state { ...@@ -185,6 +190,7 @@ struct inv_mpu6050_state {
#define INV_MPU6050_REG_INT_PIN_CFG 0x37 #define INV_MPU6050_REG_INT_PIN_CFG 0x37
#define INV_MPU6050_BIT_BYPASS_EN 0x2 #define INV_MPU6050_BIT_BYPASS_EN 0x2
#define INV_MPU6050_INT_PIN_CFG 0
/* init parameters */ /* init parameters */
#define INV_MPU6050_INIT_FIFO_RATE 50 #define INV_MPU6050_INIT_FIFO_RATE 50
...@@ -252,5 +258,10 @@ int inv_reset_fifo(struct iio_dev *indio_dev); ...@@ -252,5 +258,10 @@ int inv_reset_fifo(struct iio_dev *indio_dev);
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask); int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask);
int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val); int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on); int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st); int inv_mpu_acpi_create_mux_client(struct i2c_client *client);
void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st); void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
int (*inv_mpu_bus_setup)(struct iio_dev *));
int inv_mpu_core_remove(struct device *dev);
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
extern const struct dev_pm_ops inv_mpu_pmops;
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
...@@ -41,22 +40,23 @@ int inv_reset_fifo(struct iio_dev *indio_dev) ...@@ -41,22 +40,23 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
struct inv_mpu6050_state *st = iio_priv(indio_dev); struct inv_mpu6050_state *st = iio_priv(indio_dev);
/* disable interrupt */ /* disable interrupt */
result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); result = regmap_write(st->map, st->reg->int_enable, 0);
if (result) { if (result) {
dev_err(&st->client->dev, "int_enable failed %d\n", result); dev_err(regmap_get_device(st->map), "int_enable failed %d\n",
result);
return result; return result;
} }
/* disable the sensor output to FIFO */ /* disable the sensor output to FIFO */
result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0); result = regmap_write(st->map, st->reg->fifo_en, 0);
if (result) if (result)
goto reset_fifo_fail; goto reset_fifo_fail;
/* disable fifo reading */ /* disable fifo reading */
result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0); result = regmap_write(st->map, st->reg->user_ctrl, 0);
if (result) if (result)
goto reset_fifo_fail; goto reset_fifo_fail;
/* reset FIFO*/ /* reset FIFO*/
result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, result = regmap_write(st->map, st->reg->user_ctrl,
INV_MPU6050_BIT_FIFO_RST); INV_MPU6050_BIT_FIFO_RST);
if (result) if (result)
goto reset_fifo_fail; goto reset_fifo_fail;
...@@ -67,13 +67,13 @@ int inv_reset_fifo(struct iio_dev *indio_dev) ...@@ -67,13 +67,13 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
/* enable interrupt */ /* enable interrupt */
if (st->chip_config.accl_fifo_enable || if (st->chip_config.accl_fifo_enable ||
st->chip_config.gyro_fifo_enable) { st->chip_config.gyro_fifo_enable) {
result = inv_mpu6050_write_reg(st, st->reg->int_enable, result = regmap_write(st->map, st->reg->int_enable,
INV_MPU6050_BIT_DATA_RDY_EN); INV_MPU6050_BIT_DATA_RDY_EN);
if (result) if (result)
return result; return result;
} }
/* enable FIFO reading and I2C master interface*/ /* enable FIFO reading and I2C master interface*/
result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, result = regmap_write(st->map, st->reg->user_ctrl,
INV_MPU6050_BIT_FIFO_EN); INV_MPU6050_BIT_FIFO_EN);
if (result) if (result)
goto reset_fifo_fail; goto reset_fifo_fail;
...@@ -83,15 +83,15 @@ int inv_reset_fifo(struct iio_dev *indio_dev) ...@@ -83,15 +83,15 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
d |= INV_MPU6050_BITS_GYRO_OUT; d |= INV_MPU6050_BITS_GYRO_OUT;
if (st->chip_config.accl_fifo_enable) if (st->chip_config.accl_fifo_enable)
d |= INV_MPU6050_BIT_ACCEL_OUT; d |= INV_MPU6050_BIT_ACCEL_OUT;
result = inv_mpu6050_write_reg(st, st->reg->fifo_en, d); result = regmap_write(st->map, st->reg->fifo_en, d);
if (result) if (result)
goto reset_fifo_fail; goto reset_fifo_fail;
return 0; return 0;
reset_fifo_fail: reset_fifo_fail:
dev_err(&st->client->dev, "reset fifo failed %d\n", result); dev_err(regmap_get_device(st->map), "reset fifo failed %d\n", result);
result = inv_mpu6050_write_reg(st, st->reg->int_enable, result = regmap_write(st->map, st->reg->int_enable,
INV_MPU6050_BIT_DATA_RDY_EN); INV_MPU6050_BIT_DATA_RDY_EN);
return result; return result;
...@@ -143,10 +143,10 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) ...@@ -143,10 +143,10 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
* read fifo_count register to know how many bytes inside FIFO * read fifo_count register to know how many bytes inside FIFO
* right now * right now
*/ */
result = i2c_smbus_read_i2c_block_data(st->client, result = regmap_bulk_read(st->map,
st->reg->fifo_count_h, st->reg->fifo_count_h,
INV_MPU6050_FIFO_COUNT_BYTE, data); data, INV_MPU6050_FIFO_COUNT_BYTE);
if (result != INV_MPU6050_FIFO_COUNT_BYTE) if (result)
goto end_session; goto end_session;
fifo_count = be16_to_cpup((__be16 *)(&data[0])); fifo_count = be16_to_cpup((__be16 *)(&data[0]));
if (fifo_count < bytes_per_datum) if (fifo_count < bytes_per_datum)
...@@ -161,10 +161,9 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) ...@@ -161,10 +161,9 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR) fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR)
goto flush_fifo; goto flush_fifo;
while (fifo_count >= bytes_per_datum) { while (fifo_count >= bytes_per_datum) {
result = i2c_smbus_read_i2c_block_data(st->client, result = regmap_bulk_read(st->map, st->reg->fifo_r_w,
st->reg->fifo_r_w, data, bytes_per_datum);
bytes_per_datum, data); if (result)
if (result != bytes_per_datum)
goto flush_fifo; goto flush_fifo;
result = kfifo_out(&st->timestamps, &timestamp, 1); result = kfifo_out(&st->timestamps, &timestamp, 1);
......
/*
* Copyright (C) 2015 Intel Corporation Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include "inv_mpu_iio.h"
static const struct regmap_config inv_mpu_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static int inv_mpu_i2c_disable(struct iio_dev *indio_dev)
{
struct inv_mpu6050_state *st = iio_priv(indio_dev);
int ret = 0;
ret = inv_mpu6050_set_power_itg(st, true);
if (ret)
return ret;
ret = regmap_write(st->map, INV_MPU6050_REG_USER_CTRL,
INV_MPU6050_BIT_I2C_IF_DIS);
if (ret) {
inv_mpu6050_set_power_itg(st, false);
return ret;
}
return inv_mpu6050_set_power_itg(st, false);
}
static int inv_mpu_probe(struct spi_device *spi)
{
struct regmap *regmap;
const struct spi_device_id *id = spi_get_device_id(spi);
const char *name = id ? id->name : NULL;
regmap = devm_regmap_init_spi(spi, &inv_mpu_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Failed to register spi regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return inv_mpu_core_probe(regmap, spi->irq, name, inv_mpu_i2c_disable);
}
static int inv_mpu_remove(struct spi_device *spi)
{
return inv_mpu_core_remove(&spi->dev);
}
/*
* device id table is used to identify what device can be
* supported by this driver
*/
static const struct spi_device_id inv_mpu_id[] = {
{"mpu6000", INV_MPU6000},
{}
};
MODULE_DEVICE_TABLE(spi, inv_mpu_id);
static const struct acpi_device_id inv_acpi_match[] = {
{"INVN6000", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
static struct spi_driver inv_mpu_driver = {
.probe = inv_mpu_probe,
.remove = inv_mpu_remove,
.id_table = inv_mpu_id,
.driver = {
.acpi_match_table = ACPI_PTR(inv_acpi_match),
.name = "inv-mpu6000-spi",
.pm = &inv_mpu_pmops,
},
};
module_spi_driver(inv_mpu_driver);
MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
MODULE_DESCRIPTION("Invensense device MPU6000 driver");
MODULE_LICENSE("GPL");
...@@ -65,15 +65,15 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) ...@@ -65,15 +65,15 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
if (result) if (result)
return result; return result;
} else { } else {
result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0); result = regmap_write(st->map, st->reg->fifo_en, 0);
if (result) if (result)
return result; return result;
result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); result = regmap_write(st->map, st->reg->int_enable, 0);
if (result) if (result)
return result; return result;
result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0); result = regmap_write(st->map, st->reg->user_ctrl, 0);
if (result) if (result)
return result; return result;
...@@ -123,7 +123,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) ...@@ -123,7 +123,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
if (!st->trig) if (!st->trig)
return -ENOMEM; return -ENOMEM;
ret = devm_request_irq(&indio_dev->dev, st->client->irq, ret = devm_request_irq(&indio_dev->dev, st->irq,
&iio_trigger_generic_data_rdy_poll, &iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING, IRQF_TRIGGER_RISING,
"inv_mpu", "inv_mpu",
...@@ -131,7 +131,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) ...@@ -131,7 +131,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
if (ret) if (ret)
return ret; return ret;
st->trig->dev.parent = &st->client->dev; st->trig->dev.parent = regmap_get_device(st->map);
st->trig->ops = &inv_mpu_trigger_ops; st->trig->ops = &inv_mpu_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev); iio_trigger_set_drvdata(st->trig, indio_dev);
......
...@@ -512,33 +512,41 @@ static ssize_t iio_buffer_show_enable(struct device *dev, ...@@ -512,33 +512,41 @@ static ssize_t iio_buffer_show_enable(struct device *dev,
return sprintf(buf, "%d\n", iio_buffer_is_active(indio_dev->buffer)); return sprintf(buf, "%d\n", iio_buffer_is_active(indio_dev->buffer));
} }
static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
unsigned int scan_index)
{
const struct iio_chan_spec *ch;
unsigned int bytes;
ch = iio_find_channel_from_si(indio_dev, scan_index);
bytes = ch->scan_type.storagebits / 8;
if (ch->scan_type.repeat > 1)
bytes *= ch->scan_type.repeat;
return bytes;
}
static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
{
return iio_storage_bytes_for_si(indio_dev,
indio_dev->scan_index_timestamp);
}
static int iio_compute_scan_bytes(struct iio_dev *indio_dev, static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
const unsigned long *mask, bool timestamp) const unsigned long *mask, bool timestamp)
{ {
const struct iio_chan_spec *ch;
unsigned bytes = 0; unsigned bytes = 0;
int length, i; int length, i;
/* How much space will the demuxed element take? */ /* How much space will the demuxed element take? */
for_each_set_bit(i, mask, for_each_set_bit(i, mask,
indio_dev->masklength) { indio_dev->masklength) {
ch = iio_find_channel_from_si(indio_dev, i); length = iio_storage_bytes_for_si(indio_dev, i);
if (ch->scan_type.repeat > 1)
length = ch->scan_type.storagebits / 8 *
ch->scan_type.repeat;
else
length = ch->scan_type.storagebits / 8;
bytes = ALIGN(bytes, length); bytes = ALIGN(bytes, length);
bytes += length; bytes += length;
} }
if (timestamp) { if (timestamp) {
ch = iio_find_channel_from_si(indio_dev, length = iio_storage_bytes_for_timestamp(indio_dev);
indio_dev->scan_index_timestamp);
if (ch->scan_type.repeat > 1)
length = ch->scan_type.storagebits / 8 *
ch->scan_type.repeat;
else
length = ch->scan_type.storagebits / 8;
bytes = ALIGN(bytes, length); bytes = ALIGN(bytes, length);
bytes += length; bytes += length;
} }
...@@ -1288,7 +1296,6 @@ static int iio_buffer_add_demux(struct iio_buffer *buffer, ...@@ -1288,7 +1296,6 @@ static int iio_buffer_add_demux(struct iio_buffer *buffer,
static int iio_buffer_update_demux(struct iio_dev *indio_dev, static int iio_buffer_update_demux(struct iio_dev *indio_dev,
struct iio_buffer *buffer) struct iio_buffer *buffer)
{ {
const struct iio_chan_spec *ch;
int ret, in_ind = -1, out_ind, length; int ret, in_ind = -1, out_ind, length;
unsigned in_loc = 0, out_loc = 0; unsigned in_loc = 0, out_loc = 0;
struct iio_demux_table *p = NULL; struct iio_demux_table *p = NULL;
...@@ -1315,21 +1322,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, ...@@ -1315,21 +1322,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
in_ind = find_next_bit(indio_dev->active_scan_mask, in_ind = find_next_bit(indio_dev->active_scan_mask,
indio_dev->masklength, indio_dev->masklength,
in_ind + 1); in_ind + 1);
ch = iio_find_channel_from_si(indio_dev, in_ind); length = iio_storage_bytes_for_si(indio_dev, in_ind);
if (ch->scan_type.repeat > 1)
length = ch->scan_type.storagebits / 8 *
ch->scan_type.repeat;
else
length = ch->scan_type.storagebits / 8;
/* Make sure we are aligned */ /* Make sure we are aligned */
in_loc = roundup(in_loc, length) + length; in_loc = roundup(in_loc, length) + length;
} }
ch = iio_find_channel_from_si(indio_dev, in_ind); length = iio_storage_bytes_for_si(indio_dev, in_ind);
if (ch->scan_type.repeat > 1)
length = ch->scan_type.storagebits / 8 *
ch->scan_type.repeat;
else
length = ch->scan_type.storagebits / 8;
out_loc = roundup(out_loc, length); out_loc = roundup(out_loc, length);
in_loc = roundup(in_loc, length); in_loc = roundup(in_loc, length);
ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
...@@ -1340,13 +1337,7 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, ...@@ -1340,13 +1337,7 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
} }
/* Relies on scan_timestamp being last */ /* Relies on scan_timestamp being last */
if (buffer->scan_timestamp) { if (buffer->scan_timestamp) {
ch = iio_find_channel_from_si(indio_dev, length = iio_storage_bytes_for_timestamp(indio_dev);
indio_dev->scan_index_timestamp);
if (ch->scan_type.repeat > 1)
length = ch->scan_type.storagebits / 8 *
ch->scan_type.repeat;
else
length = ch->scan_type.storagebits / 8;
out_loc = roundup(out_loc, length); out_loc = roundup(out_loc, length);
in_loc = roundup(in_loc, length); in_loc = roundup(in_loc, length);
ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
......
...@@ -69,6 +69,7 @@ config MPL3115 ...@@ -69,6 +69,7 @@ config MPL3115
config MS5611 config MS5611
tristate "Measurement Specialties MS5611 pressure sensor driver" tristate "Measurement Specialties MS5611 pressure sensor driver"
select IIO_TRIGGERED_BUFFER
help help
Say Y here to build support for the Measurement Specialties Say Y here to build support for the Measurement Specialties
MS5611, MS5607 pressure and temperature sensors. MS5611, MS5607 pressure and temperature sensors.
......
...@@ -52,5 +52,6 @@ struct ms5611_state { ...@@ -52,5 +52,6 @@ struct ms5611_state {
}; };
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type); int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type);
int ms5611_remove(struct iio_dev *indio_dev);
#endif /* _MS5611_H */ #endif /* _MS5611_H */
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include "ms5611.h" #include "ms5611.h"
static bool ms5611_prom_is_valid(u16 *prom, size_t len) static bool ms5611_prom_is_valid(u16 *prom, size_t len)
...@@ -173,6 +176,28 @@ static int ms5611_reset(struct iio_dev *indio_dev) ...@@ -173,6 +176,28 @@ static int ms5611_reset(struct iio_dev *indio_dev)
return 0; return 0;
} }
static irqreturn_t ms5611_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ms5611_state *st = iio_priv(indio_dev);
s32 buf[4]; /* s32 (pressure) + s32 (temp) + 2 * s32 (timestamp) */
int ret;
mutex_lock(&st->lock);
ret = ms5611_read_temp_and_pressure(indio_dev, &buf[1], &buf[0]);
mutex_unlock(&st->lock);
if (ret < 0)
goto err;
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
err:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ms5611_read_raw(struct iio_dev *indio_dev, static int ms5611_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, struct iio_chan_spec const *chan,
int *val, int *val2, long mask) int *val, int *val2, long mask)
...@@ -201,11 +226,25 @@ static int ms5611_read_raw(struct iio_dev *indio_dev, ...@@ -201,11 +226,25 @@ static int ms5611_read_raw(struct iio_dev *indio_dev,
default: default:
return -EINVAL; return -EINVAL;
} }
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_TEMP:
*val = 10;
return IIO_VAL_INT;
case IIO_PRESSURE:
*val = 0;
*val2 = 1000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
} }
return -EINVAL; return -EINVAL;
} }
static const unsigned long ms5611_scan_masks[] = {0x3, 0};
static struct ms5611_chip_info chip_info_tbl[] = { static struct ms5611_chip_info chip_info_tbl[] = {
[MS5611] = { [MS5611] = {
.temp_and_pressure_compensate = ms5611_temp_and_pressure_compensate, .temp_and_pressure_compensate = ms5611_temp_and_pressure_compensate,
...@@ -218,12 +257,29 @@ static struct ms5611_chip_info chip_info_tbl[] = { ...@@ -218,12 +257,29 @@ static struct ms5611_chip_info chip_info_tbl[] = {
static const struct iio_chan_spec ms5611_channels[] = { static const struct iio_chan_spec ms5611_channels[] = {
{ {
.type = IIO_PRESSURE, .type = IIO_PRESSURE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_CPU,
},
}, },
{ {
.type = IIO_TEMP, .type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
} BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 1,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_CPU,
},
},
IIO_CHAN_SOFT_TIMESTAMP(2),
}; };
static const struct iio_info ms5611_info = { static const struct iio_info ms5611_info = {
...@@ -255,15 +311,43 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type) ...@@ -255,15 +311,43 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type)
indio_dev->channels = ms5611_channels; indio_dev->channels = ms5611_channels;
indio_dev->num_channels = ARRAY_SIZE(ms5611_channels); indio_dev->num_channels = ARRAY_SIZE(ms5611_channels);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->available_scan_masks = ms5611_scan_masks;
ret = ms5611_init(indio_dev); ret = ms5611_init(indio_dev);
if (ret < 0) if (ret < 0)
return ret; return ret;
return devm_iio_device_register(dev, indio_dev); ret = iio_triggered_buffer_setup(indio_dev, NULL,
ms5611_trigger_handler, NULL);
if (ret < 0) {
dev_err(dev, "iio triggered buffer setup failed\n");
return ret;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(dev, "unable to register iio device\n");
goto err_buffer_cleanup;
}
return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
} }
EXPORT_SYMBOL(ms5611_probe); EXPORT_SYMBOL(ms5611_probe);
int ms5611_remove(struct iio_dev *indio_dev)
{
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
}
EXPORT_SYMBOL(ms5611_remove);
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("MS5611 core driver"); MODULE_DESCRIPTION("MS5611 core driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -99,6 +99,7 @@ static int ms5611_i2c_probe(struct i2c_client *client, ...@@ -99,6 +99,7 @@ static int ms5611_i2c_probe(struct i2c_client *client,
return -ENOMEM; return -ENOMEM;
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
st->reset = ms5611_i2c_reset; st->reset = ms5611_i2c_reset;
st->read_prom_word = ms5611_i2c_read_prom_word; st->read_prom_word = ms5611_i2c_read_prom_word;
st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure; st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure;
...@@ -107,6 +108,11 @@ static int ms5611_i2c_probe(struct i2c_client *client, ...@@ -107,6 +108,11 @@ static int ms5611_i2c_probe(struct i2c_client *client,
return ms5611_probe(indio_dev, &client->dev, id->driver_data); return ms5611_probe(indio_dev, &client->dev, id->driver_data);
} }
static int ms5611_i2c_remove(struct i2c_client *client)
{
return ms5611_remove(i2c_get_clientdata(client));
}
static const struct i2c_device_id ms5611_id[] = { static const struct i2c_device_id ms5611_id[] = {
{ "ms5611", MS5611 }, { "ms5611", MS5611 },
{ "ms5607", MS5607 }, { "ms5607", MS5607 },
...@@ -120,6 +126,7 @@ static struct i2c_driver ms5611_driver = { ...@@ -120,6 +126,7 @@ static struct i2c_driver ms5611_driver = {
}, },
.id_table = ms5611_id, .id_table = ms5611_id,
.probe = ms5611_i2c_probe, .probe = ms5611_i2c_probe,
.remove = ms5611_i2c_remove,
}; };
module_i2c_driver(ms5611_driver); module_i2c_driver(ms5611_driver);
......
...@@ -90,6 +90,8 @@ static int ms5611_spi_probe(struct spi_device *spi) ...@@ -90,6 +90,8 @@ static int ms5611_spi_probe(struct spi_device *spi)
if (!indio_dev) if (!indio_dev)
return -ENOMEM; return -ENOMEM;
spi_set_drvdata(spi, indio_dev);
spi->mode = SPI_MODE_0; spi->mode = SPI_MODE_0;
spi->max_speed_hz = 20000000; spi->max_speed_hz = 20000000;
spi->bits_per_word = 8; spi->bits_per_word = 8;
...@@ -107,6 +109,11 @@ static int ms5611_spi_probe(struct spi_device *spi) ...@@ -107,6 +109,11 @@ static int ms5611_spi_probe(struct spi_device *spi)
spi_get_device_id(spi)->driver_data); spi_get_device_id(spi)->driver_data);
} }
static int ms5611_spi_remove(struct spi_device *spi)
{
return ms5611_remove(spi_get_drvdata(spi));
}
static const struct spi_device_id ms5611_id[] = { static const struct spi_device_id ms5611_id[] = {
{ "ms5611", MS5611 }, { "ms5611", MS5611 },
{ "ms5607", MS5607 }, { "ms5607", MS5607 },
...@@ -120,6 +127,7 @@ static struct spi_driver ms5611_driver = { ...@@ -120,6 +127,7 @@ static struct spi_driver ms5611_driver = {
}, },
.id_table = ms5611_id, .id_table = ms5611_id,
.probe = ms5611_spi_probe, .probe = ms5611_spi_probe,
.remove = ms5611_spi_remove,
}; };
module_spi_driver(ms5611_driver); module_spi_driver(ms5611_driver);
......
...@@ -59,12 +59,12 @@ config AD7816 ...@@ -59,12 +59,12 @@ config AD7816
temperature sensors and ADC. temperature sensors and ADC.
config AD7192 config AD7192
tristate "Analog Devices AD7190 AD7192 AD7195 ADC driver" tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver"
depends on SPI depends on SPI
select AD_SIGMA_DELTA select AD_SIGMA_DELTA
help help
Say yes here to build support for Analog Devices AD7190, Say yes here to build support for Analog Devices AD7190,
AD7192 or AD7195 SPI analog to digital converters (ADC). AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC).
If unsure, say N (but it's safe to say "Y"). If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
...@@ -92,20 +92,6 @@ config LPC32XX_ADC ...@@ -92,20 +92,6 @@ config LPC32XX_ADC
activate only one via device tree selection. Provides direct access activate only one via device tree selection. Provides direct access
via sysfs. via sysfs.
config MXS_LRADC
tristate "Freescale i.MX23/i.MX28 LRADC"
depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
depends on INPUT
select STMP_DEVICE
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for i.MX23/i.MX28 LRADC convertor
built into these chips.
To compile this driver as a module, choose M here: the
module will be called mxs-lradc.
config SPEAR_ADC config SPEAR_ADC
tristate "ST SPEAr ADC" tristate "ST SPEAr ADC"
depends on PLAT_SPEAR || COMPILE_TEST depends on PLAT_SPEAR || COMPILE_TEST
......
...@@ -12,5 +12,4 @@ obj-$(CONFIG_AD7816) += ad7816.o ...@@ -12,5 +12,4 @@ obj-$(CONFIG_AD7816) += ad7816.o
obj-$(CONFIG_AD7192) += ad7192.o obj-$(CONFIG_AD7192) += ad7192.o
obj-$(CONFIG_AD7280) += ad7280a.o obj-$(CONFIG_AD7280) += ad7280a.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment