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

Jonathan writes:

Second set of new device support, features and cleanup for IIO in the 4.18 cycle

Usual mixture of new devices support and other stuff.  A couple of
staging graduations in here and some old driver drops.

New device support
* ad5686
  - Add support for AD5691R, AD5692R, AD5693 and AD5693R i2c DACs
  - Add support for AD5681R, AD5682R, AD5683 and AD5683R SPI DACs
* lmp91000
  - Add ID for LMP91002
* stm32-dfsdm
  - Add support for the stm32mp1 devices.

Drivers dropped
* ADE7753
  - No longer easily available, no users came forward and needs a lot
    of work to move out of staging.
* ADE7754
* ADE7758
* ADE7759

Staging graduations
- ad2s1200 - good cleanup from David Veenstra.
- tsl2772 (was tsl2x7x) - Brian's quest is at an end and
  staging/iio/light is no more!

Features
* tools
  - loop forever on a negative number of loops being specified.
* ltc 2632
  - add of_match_table
  - support an external reference regulator.
* mag3110
  - Support continuous mode when running fast as it increases the
    posssible sampling rate.
* ti-ads8688
  - Add trigger and buffer support to this ADC.

Cleanups / minor tweaks.
* tools
  - tidy up types in iio_generic_buffer.
* ad2s1200
  - Whitespace cleanup.
  - Drop pointless initializations.
  - Improve kernel docs.
  - Reorder to setup the SPI prior to device registration (race fix).
  - Change to modern gpiod framework.
  - Drop platform data and move to DT bindings. There are no in
    kernel users of the platform data. Any out of tree boards will
    need changes.
  - Add an explicit compatible table.
  - Provide _scale for angular velocity and angle channels.
  - Add David Veenstra to copyright notice as this cleanup was non
    trivial.
* ade8366
  - Avoid a race by ensuring channel init is before registration
    with the subsystem.
* afe
  - binding spelling fix.
* imx7d-adc
  - typo fix in Freescale
* inv_mpu6050
  - tidy up an ugly loop to take advantage of known entry condition.
  - add a comment explaining why the sensible sampling frequencies
    are more limited than might be immediately apparent (aliasing).
* mma8452
  - reduce the sleep time on data not ready when running at high
    frequency.
* stm32-dfsdm
  - add missing header.
* tsl2583
  - fix integration_time_availabe which was in microsecs rather the
    millisecs.
* tsl2x7x/tsl2772
  - Whitespace cleanup.
  - Change to direct returns where sensible.
  - Turn the chip off in the registration error path.
  - Use macro to reduce repition when setting up the device_info
    structures.
  - Change the _available attributes over to read_avail callback,
    and the range definitions that supports.
  - Fix some wrong period values.
  - Add some range checkign for _write_raw.
  - Rename the driver to tsl2772 to avoid wild card clash problems
    in future.
This commit is contained in:
Greg Kroah-Hartman
2018-05-25 18:07:31 +02:00
47 changed files with 1143 additions and 3930 deletions

View File

@@ -8,14 +8,16 @@ It is mainly targeted for:
- PDM microphones (audio digital microphone)
It features up to 8 serial digital interfaces (SPI or Manchester) and
up to 4 filters on stm32h7.
up to 4 filters on stm32h7 or 6 filters on stm32mp1.
Each child node match with a filter instance.
Contents of a STM32 DFSDM root node:
------------------------------------
Required properties:
- compatible: Should be "st,stm32h7-dfsdm".
- compatible: Should be one of:
"st,stm32h7-dfsdm"
"st,stm32mp1-dfsdm"
- reg: Offset and length of the DFSDM block register set.
- clocks: IP and serial interfaces clocking. Should be set according
to rcc clock ID and "clock-names".
@@ -45,6 +47,7 @@ Required properties:
"st,stm32-dfsdm-adc" for sigma delta ADCs
"st,stm32-dfsdm-dmic" for audio digital microphone.
- reg: Specifies the DFSDM filter instance used.
Valid values are from 0 to 3 on stm32h7, 0 to 5 on stm32mp1.
- interrupts: IRQ lines connected to each DFSDM filter instance.
- st,adc-channels: List of single-ended channels muxed for this ADC.
valid values:

View File

@@ -2,7 +2,7 @@ Current Sense Amplifier
=======================
When an io-channel measures the output voltage from a current sense
amplifier, the interesting mesaurement is almost always the current
amplifier, the interesting measurement is almost always the current
through the sense resistor, not the voltage output. This binding
describes such a current sense circuit.

View File

@@ -2,7 +2,7 @@ Current Sense Shunt
===================
When an io-channel measures the voltage over a current sense shunt,
the interesting mesaurement is almost always the current through the
the interesting measurement is almost always the current through the
shunt, not the voltage over it. This binding describes such a current
sense circuit.

View File

@@ -12,12 +12,26 @@ Required properties:
Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
apply. In particular, "reg" and "spi-max-frequency" properties must be given.
Optional properties:
- vref-supply: Phandle to the external reference voltage supply. This should
only be set if there is an external reference voltage connected to the VREF
pin. If the property is not set the internal reference is used.
Example:
vref: regulator-vref {
compatible = "regulator-fixed";
regulator-name = "vref-ltc2632";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <1250000>;
regulator-always-on;
};
spi_master {
dac: ltc2632@0 {
compatible = "lltc,ltc2632-l12";
reg = <0>; /* CS0 */
spi-max-frequency = <1000000>;
vref-supply = <&vref>; /* optional */
};
};

View File

@@ -1,10 +1,13 @@
* Texas Instruments LMP91000 potentiostat
* Texas Instruments LMP91000 series of potentiostats
http://www.ti.com/lit/ds/symlink/lmp91000.pdf
LMP91000: http://www.ti.com/lit/ds/symlink/lmp91000.pdf
LMP91002: http://www.ti.com/lit/ds/symlink/lmp91002.pdf
Required properties:
- compatible: should be "ti,lmp91000"
- compatible: should be one of the following:
"ti,lmp91000"
"ti,lmp91002"
- reg: the I2C address of the device
- io-channels: the phandle of the iio provider

View File

@@ -93,6 +93,7 @@ source "drivers/iio/potentiometer/Kconfig"
source "drivers/iio/potentiostat/Kconfig"
source "drivers/iio/pressure/Kconfig"
source "drivers/iio/proximity/Kconfig"
source "drivers/iio/resolver/Kconfig"
source "drivers/iio/temperature/Kconfig"
endif # IIO

View File

@@ -36,5 +36,6 @@ obj-y += potentiometer/
obj-y += potentiostat/
obj-y += pressure/
obj-y += proximity/
obj-y += resolver/
obj-y += temperature/
obj-y += trigger/

View File

@@ -106,6 +106,7 @@ struct mma8452_data {
u8 ctrl_reg1;
u8 data_cfg;
const struct mma_chip_info *chip_info;
int sleep_val;
};
/**
@@ -193,7 +194,11 @@ static int mma8452_drdy(struct mma8452_data *data)
if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
return 0;
msleep(20);
if (data->sleep_val <= 20)
usleep_range(data->sleep_val * 250,
data->sleep_val * 500);
else
msleep(20);
}
dev_err(&data->client->dev, "data not ready\n");
@@ -544,6 +549,18 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
static int mma8452_calculate_sleep(struct mma8452_data *data)
{
int ret, i = mma8452_get_odr_index(data);
if (mma8452_samp_freq[i][0] > 0)
ret = 1000 / mma8452_samp_freq[i][0];
else
ret = 1000;
return ret == 0 ? 1 : ret;
}
static int mma8452_standby(struct mma8452_data *data)
{
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
@@ -700,6 +717,8 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
data->sleep_val = mma8452_calculate_sleep(data);
ret = mma8452_change_config(data, MMA8452_CTRL_REG1,
data->ctrl_reg1);
break;
@@ -1593,6 +1612,9 @@ static int mma8452_probe(struct i2c_client *client,
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
data->sleep_val = mma8452_calculate_sleep(data);
ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
data->ctrl_reg1);
if (ret < 0)

View File

@@ -604,5 +604,5 @@ static struct platform_driver imx7d_adc_driver = {
module_platform_driver(imx7d_adc_driver);
MODULE_AUTHOR("Haibo Chen <haibo.chen@freescale.com>");
MODULE_DESCRIPTION("Freeacale IMX7D ADC driver");
MODULE_DESCRIPTION("Freescale IMX7D ADC driver");
MODULE_LICENSE("GPL v2");

View File

@@ -8,11 +8,11 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/iio/adc/stm32-dfsdm-adc.h>
#include <linux/iio/buffer.h>
#include <linux/iio/hw-consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>

View File

@@ -25,6 +25,8 @@ struct stm32_dfsdm_dev_data {
#define STM32H7_DFSDM_NUM_FILTERS 4
#define STM32H7_DFSDM_NUM_CHANNELS 8
#define STM32MP1_DFSDM_NUM_FILTERS 6
#define STM32MP1_DFSDM_NUM_CHANNELS 8
static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg)
{
@@ -61,6 +63,21 @@ static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_data = {
.regmap_cfg = &stm32h7_dfsdm_regmap_cfg,
};
static const struct regmap_config stm32mp1_dfsdm_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = sizeof(u32),
.max_register = 0x7fc,
.volatile_reg = stm32_dfsdm_volatile_reg,
.fast_io = true,
};
static const struct stm32_dfsdm_dev_data stm32mp1_dfsdm_data = {
.num_filters = STM32MP1_DFSDM_NUM_FILTERS,
.num_channels = STM32MP1_DFSDM_NUM_CHANNELS,
.regmap_cfg = &stm32mp1_dfsdm_regmap_cfg,
};
struct dfsdm_priv {
struct platform_device *pdev; /* platform device */
@@ -248,6 +265,10 @@ static const struct of_device_id stm32_dfsdm_of_match[] = {
.compatible = "st,stm32h7-dfsdm",
.data = &stm32h7_dfsdm_data,
},
{
.compatible = "st,stm32mp1-dfsdm",
.data = &stm32mp1_dfsdm_data,
},
{}
};
MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match);

View File

@@ -17,6 +17,9 @@
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/sysfs.h>
#define ADS8688_CMD_REG(x) (x << 8)
@@ -155,6 +158,13 @@ static const struct attribute_group ads8688_attribute_group = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
| BIT(IIO_CHAN_INFO_SCALE) \
| BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec ads8684_channels[] = {
@@ -371,6 +381,28 @@ static const struct iio_info ads8688_info = {
.attrs = &ads8688_attribute_group,
};
static irqreturn_t ads8688_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
u16 buffer[8];
int i, j = 0;
for (i = 0; i < indio_dev->masklength; i++) {
if (!test_bit(i, indio_dev->active_scan_mask))
continue;
buffer[j] = ads8688_read(indio_dev, i);
j++;
}
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static const struct ads8688_chip_info ads8688_chip_info_tbl[] = {
[ID_ADS8684] = {
.channels = ads8684_channels,
@@ -402,7 +434,7 @@ static int ads8688_probe(struct spi_device *spi)
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_out;
goto err_regulator_disable;
st->vref_mv = ret / 1000;
} else {
@@ -430,13 +462,22 @@ static int ads8688_probe(struct spi_device *spi)
mutex_init(&st->lock);
ret = iio_triggered_buffer_setup(indio_dev, NULL, ads8688_trigger_handler, NULL);
if (ret < 0) {
dev_err(&spi->dev, "iio triggered buffer setup failed\n");
goto err_regulator_disable;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_out;
goto err_buffer_cleanup;
return 0;
error_out:
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
err_regulator_disable:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
@@ -449,6 +490,7 @@ static int ads8688_remove(struct spi_device *spi)
struct ads8688_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);

View File

@@ -161,12 +161,14 @@ static int ad8366_probe(struct spi_device *spi)
indio_dev->channels = ad8366_channels;
indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
ret = ad8366_write(indio_dev, 0 , 0);
if (ret < 0)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
ad8366_write(indio_dev, 0, 0);
return 0;
error_disable_reg:

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* AD5672R, AD5676, AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R
* AD5672R, AD5676, AD5676R, AD5681R, AD5682R, AD5683, AD5683R,
* AD5684, AD5684R, AD5685R, AD5686, AD5686R
* Digital to analog converters driver
*
* Copyright 2018 Analog Devices Inc.
@@ -15,12 +16,27 @@ static int ad5686_spi_write(struct ad5686_state *st,
u8 cmd, u8 addr, u16 val)
{
struct spi_device *spi = to_spi_device(st->dev);
u8 tx_len, *buf;
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
AD5686_ADDR(addr) |
val);
switch (st->chip_info->regmap_type) {
case AD5683_REGMAP:
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
AD5683_DATA(val));
buf = &st->data[0].d8[1];
tx_len = 3;
break;
case AD5686_REGMAP:
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
AD5686_ADDR(addr) |
val);
buf = &st->data[0].d8[1];
tx_len = 3;
break;
default:
return -EINVAL;
}
return spi_write(spi, &st->data[0].d8[1], 3);
return spi_write(spi, buf, tx_len);
}
static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
@@ -37,9 +53,15 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
},
};
struct spi_device *spi = to_spi_device(st->dev);
u8 cmd = 0;
int ret;
st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
if (st->chip_info->regmap_type == AD5686_REGMAP)
cmd = AD5686_CMD_READBACK_ENABLE;
else if (st->chip_info->regmap_type == AD5683_REGMAP)
cmd = AD5686_CMD_READBACK_ENABLE_V2;
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
AD5686_ADDR(addr));
st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
@@ -67,6 +89,10 @@ static const struct spi_device_id ad5686_spi_id[] = {
{"ad5672r", ID_AD5672R},
{"ad5676", ID_AD5676},
{"ad5676r", ID_AD5676R},
{"ad5681r", ID_AD5681R},
{"ad5682r", ID_AD5682R},
{"ad5683", ID_AD5683},
{"ad5683r", ID_AD5683R},
{"ad5684", ID_AD5684},
{"ad5684r", ID_AD5684R},
{"ad5685", ID_AD5685R}, /* Does not exist */

View File

@@ -70,6 +70,8 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
bool readin;
int ret;
struct ad5686_state *st = iio_priv(indio_dev);
unsigned int val, ref_bit_msk;
u8 shift;
ret = strtobool(buf, &readin);
if (ret)
@@ -80,9 +82,28 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
else
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, 0,
st->pwr_down_mask & st->pwr_down_mode);
switch (st->chip_info->regmap_type) {
case AD5683_REGMAP:
shift = 13;
ref_bit_msk = AD5683_REF_BIT_MSK;
break;
case AD5686_REGMAP:
shift = 0;
ref_bit_msk = 0;
break;
case AD5693_REGMAP:
shift = 13;
ref_bit_msk = AD5693_REF_BIT_MSK;
break;
default:
return -EINVAL;
}
val = ((st->pwr_down_mask & st->pwr_down_mode) << shift);
if (!st->use_internal_vref)
val |= ref_bit_msk;
ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, 0, val);
return ret ? ret : len;
}
@@ -175,6 +196,11 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
.ext_info = ad5686_ext_info, \
}
#define DECLARE_AD5693_CHANNELS(name, bits, _shift) \
static struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 0, bits, _shift), \
}
#define DECLARE_AD5686_CHANNELS(name, bits, _shift) \
static struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 1, bits, _shift), \
@@ -200,72 +226,135 @@ DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4);
DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2);
DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0);
DECLARE_AD5693_CHANNELS(ad5693_channels, 16, 0);
DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2);
DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4);
static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
[ID_AD5671R] = {
.channels = ad5672_channels,
.int_vref_mv = 2500,
.num_channels = 8,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5672R] = {
.channels = ad5672_channels,
.int_vref_mv = 2500,
.num_channels = 8,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5675R] = {
.channels = ad5676_channels,
.int_vref_mv = 2500,
.num_channels = 8,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5676] = {
.channels = ad5676_channels,
.num_channels = 8,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5676R] = {
.channels = ad5676_channels,
.int_vref_mv = 2500,
.num_channels = 8,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5681R] = {
.channels = ad5691r_channels,
.int_vref_mv = 2500,
.num_channels = 1,
.regmap_type = AD5683_REGMAP,
},
[ID_AD5682R] = {
.channels = ad5692r_channels,
.int_vref_mv = 2500,
.num_channels = 1,
.regmap_type = AD5683_REGMAP,
},
[ID_AD5683] = {
.channels = ad5693_channels,
.num_channels = 1,
.regmap_type = AD5683_REGMAP,
},
[ID_AD5683R] = {
.channels = ad5693_channels,
.int_vref_mv = 2500,
.num_channels = 1,
.regmap_type = AD5683_REGMAP,
},
[ID_AD5684] = {
.channels = ad5684_channels,
.num_channels = 4,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5684R] = {
.channels = ad5684_channels,
.int_vref_mv = 2500,
.num_channels = 4,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5685R] = {
.channels = ad5685r_channels,
.int_vref_mv = 2500,
.num_channels = 4,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5686] = {
.channels = ad5686_channels,
.num_channels = 4,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5686R] = {
.channels = ad5686_channels,
.int_vref_mv = 2500,
.num_channels = 4,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5691R] = {
.channels = ad5691r_channels,
.int_vref_mv = 2500,
.num_channels = 1,
.regmap_type = AD5693_REGMAP,
},
[ID_AD5692R] = {
.channels = ad5692r_channels,
.int_vref_mv = 2500,
.num_channels = 1,
.regmap_type = AD5693_REGMAP,
},
[ID_AD5693] = {
.channels = ad5693_channels,
.num_channels = 1,
.regmap_type = AD5693_REGMAP,
},
[ID_AD5693R] = {
.channels = ad5693_channels,
.int_vref_mv = 2500,
.num_channels = 1,
.regmap_type = AD5693_REGMAP,
},
[ID_AD5694] = {
.channels = ad5684_channels,
.num_channels = 4,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5694R] = {
.channels = ad5684_channels,
.int_vref_mv = 2500,
.num_channels = 4,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5696] = {
.channels = ad5686_channels,
.num_channels = 4,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5696R] = {
.channels = ad5686_channels,
.int_vref_mv = 2500,
.num_channels = 4,
.regmap_type = AD5686_REGMAP,
},
};
@@ -276,7 +365,9 @@ int ad5686_probe(struct device *dev,
{
struct ad5686_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
unsigned int val, ref_bit_msk;
u8 cmd;
int ret, i, voltage_uv = 0;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL)
@@ -310,7 +401,8 @@ int ad5686_probe(struct device *dev,
st->vref_mv = st->chip_info->int_vref_mv;
/* Set all the power down mode for all channels to 1K pulldown */
st->pwr_down_mode = 0x55;
for (i = 0; i < st->chip_info->num_channels; i++)
st->pwr_down_mode |= (0x01 << (i * 2));
indio_dev->dev.parent = dev;
indio_dev->name = name;
@@ -319,8 +411,29 @@ int ad5686_probe(struct device *dev,
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
ret = st->write(st, AD5686_CMD_INTERNAL_REFER_SETUP,
0, !!voltage_uv);
switch (st->chip_info->regmap_type) {
case AD5683_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
ref_bit_msk = AD5683_REF_BIT_MSK;
st->use_internal_vref = !voltage_uv;
break;
case AD5686_REGMAP:
cmd = AD5686_CMD_INTERNAL_REFER_SETUP;
ref_bit_msk = 0;
break;
case AD5693_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
ref_bit_msk = AD5693_REF_BIT_MSK;
st->use_internal_vref = !voltage_uv;
break;
default:
ret = -EINVAL;
goto error_disable_reg;
}
val = (voltage_uv | ref_bit_msk);
ret = st->write(st, cmd, 0, !!val);
if (ret)
goto error_disable_reg;

View File

@@ -13,6 +13,7 @@
#include <linux/mutex.h>
#include <linux/kernel.h>
#define AD5683_DATA(x) ((x) << 4)
#define AD5686_ADDR(x) ((x) << 16)
#define AD5686_CMD(x) ((x) << 20)
@@ -35,6 +36,11 @@
#define AD5686_LDAC_PWRDN_100K 0x2
#define AD5686_LDAC_PWRDN_3STATE 0x3
#define AD5686_CMD_CONTROL_REG 0x4
#define AD5686_CMD_READBACK_ENABLE_V2 0x5
#define AD5683_REF_BIT_MSK BIT(12)
#define AD5693_REF_BIT_MSK BIT(12)
/**
* ad5686_supported_device_ids:
*/
@@ -44,11 +50,19 @@ enum ad5686_supported_device_ids {
ID_AD5675R,
ID_AD5676,
ID_AD5676R,
ID_AD5681R,
ID_AD5682R,
ID_AD5683,
ID_AD5683R,
ID_AD5684,
ID_AD5684R,
ID_AD5685R,
ID_AD5686,
ID_AD5686R,
ID_AD5691R,
ID_AD5692R,
ID_AD5693,
ID_AD5693R,
ID_AD5694,
ID_AD5694R,
ID_AD5695R,
@@ -56,6 +70,12 @@ enum ad5686_supported_device_ids {
ID_AD5696R,
};
enum ad5686_regmap_type {
AD5683_REGMAP,
AD5686_REGMAP,
AD5693_REGMAP
};
struct ad5686_state;
typedef int (*ad5686_write_func)(struct ad5686_state *st,
@@ -68,12 +88,14 @@ typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr);
* @int_vref_mv: AD5620/40/60: the internal reference voltage
* @num_channels: number of channels
* @channel: channel specification
* @regmap_type: register map layout variant
*/
struct ad5686_chip_info {
u16 int_vref_mv;
unsigned int num_channels;
struct iio_chan_spec *channels;
enum ad5686_regmap_type regmap_type;
};
/**
@@ -84,6 +106,7 @@ struct ad5686_chip_info {
* @vref_mv: actual reference voltage used
* @pwr_down_mask: power down mask
* @pwr_down_mode: current power down mode
* @use_internal_vref: set to true if the internal reference voltage is used
* @data: spi transfer buffers
*/
@@ -96,6 +119,7 @@ struct ad5686_state {
unsigned int pwr_down_mode;
ad5686_write_func write;
ad5686_read_func read;
bool use_internal_vref;
/*
* DMA (thus cache coherency maintenance) requires the

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* AD5671R, AD5675R, AD5694, AD5694R, AD5695R, AD5696, AD5696R
* AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R,
* AD5694, AD5694R, AD5695R, AD5696, AD5696R
* Digital to analog converters driver
*
* Copyright 2018 Analog Devices Inc.
@@ -72,6 +73,10 @@ static int ad5686_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id ad5686_i2c_id[] = {
{"ad5671r", ID_AD5671R},
{"ad5675r", ID_AD5675R},
{"ad5691r", ID_AD5691R},
{"ad5692r", ID_AD5692R},
{"ad5693", ID_AD5693},
{"ad5693r", ID_AD5693R},
{"ad5694", ID_AD5694},
{"ad5694r", ID_AD5694R},
{"ad5695r", ID_AD5695R},

View File

@@ -2,6 +2,7 @@
* LTC2632 Digital to analog convertors spi driver
*
* Copyright 2017 Maxime Roussin-Bélanger
* expanded by Silvan Murer <silvan.murer@gmail.com>
*
* Licensed under the GPL-2.
*/
@@ -10,6 +11,7 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
#define LTC2632_DAC_CHANNELS 2
@@ -28,7 +30,7 @@
/**
* struct ltc2632_chip_info - chip specific information
* @channels: channel spec for the DAC
* @vref_mv: reference voltage
* @vref_mv: internal reference voltage
*/
struct ltc2632_chip_info {
const struct iio_chan_spec *channels;
@@ -39,10 +41,14 @@ struct ltc2632_chip_info {
* struct ltc2632_state - driver instance specific data
* @spi_dev: pointer to the spi_device struct
* @powerdown_cache_mask used to show current channel powerdown state
* @vref_mv used reference voltage (internal or external)
* @vref_reg regulator for the reference voltage
*/
struct ltc2632_state {
struct spi_device *spi_dev;
unsigned int powerdown_cache_mask;
int vref_mv;
struct regulator *vref_reg;
};
enum ltc2632_supported_device_ids {
@@ -90,7 +96,7 @@ static int ltc2632_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_SCALE:
*val = chip_info->vref_mv;
*val = st->vref_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
@@ -246,6 +252,45 @@ static int ltc2632_probe(struct spi_device *spi)
chip_info = (struct ltc2632_chip_info *)
spi_get_device_id(spi)->driver_data;
st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
if (PTR_ERR(st->vref_reg) == -ENODEV) {
/* use internal reference voltage */
st->vref_reg = NULL;
st->vref_mv = chip_info->vref_mv;
ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER,
0, 0, 0);
if (ret) {
dev_err(&spi->dev,
"Set internal reference command failed, %d\n",
ret);
return ret;
}
} else if (IS_ERR(st->vref_reg)) {
dev_err(&spi->dev,
"Error getting voltage reference regulator\n");
return PTR_ERR(st->vref_reg);
} else {
/* use external reference voltage */
ret = regulator_enable(st->vref_reg);
if (ret) {
dev_err(&spi->dev,
"enable reference regulator failed, %d\n",
ret);
return ret;
}
st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000;
ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER,
0, 0, 0);
if (ret) {
dev_err(&spi->dev,
"Set external reference command failed, %d\n",
ret);
return ret;
}
}
indio_dev->dev.parent = &spi->dev;
indio_dev->name = dev_of_node(&spi->dev) ? dev_of_node(&spi->dev)->name
: spi_get_device_id(spi)->name;
@@ -254,14 +299,20 @@ static int ltc2632_probe(struct spi_device *spi)
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = LTC2632_DAC_CHANNELS;
ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER, 0, 0, 0);
if (ret) {
dev_err(&spi->dev,
"Set internal reference command failed, %d\n", ret);
return ret;
}
return iio_device_register(indio_dev);
}
return devm_iio_device_register(&spi->dev, indio_dev);
static int ltc2632_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ltc2632_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (st->vref_reg)
regulator_disable(st->vref_reg);
return 0;
}
static const struct spi_device_id ltc2632_id[] = {
@@ -275,15 +326,6 @@ static const struct spi_device_id ltc2632_id[] = {
};
MODULE_DEVICE_TABLE(spi, ltc2632_id);
static struct spi_driver ltc2632_driver = {
.driver = {
.name = "ltc2632",
},
.probe = ltc2632_probe,
.id_table = ltc2632_id,
};
module_spi_driver(ltc2632_driver);
static const struct of_device_id ltc2632_of_match[] = {
{
.compatible = "lltc,ltc2632-l12",
@@ -308,6 +350,17 @@ static const struct of_device_id ltc2632_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ltc2632_of_match);
static struct spi_driver ltc2632_driver = {
.driver = {
.name = "ltc2632",
.of_match_table = of_match_ptr(ltc2632_of_match),
},
.probe = ltc2632_probe,
.remove = ltc2632_remove,
.id_table = ltc2632_id,
};
module_spi_driver(ltc2632_driver);
MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>");
MODULE_DESCRIPTION("LTC2632 DAC SPI driver");
MODULE_LICENSE("GPL v2");

View File

@@ -798,7 +798,14 @@ static const struct iio_chan_spec inv_mpu_channels[] = {
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),
};
/* constant IIO attribute */
/*
* The user can choose any frequency between INV_MPU6050_MIN_FIFO_RATE and
* INV_MPU6050_MAX_FIFO_RATE, but only these frequencies are matched by the
* low-pass filter. Specifically, each of these sampling rates are about twice
* the bandwidth of a corresponding low-pass filter, which should eliminate
* aliasing following the Nyquist principle. By picking a frequency different
* from these, the user risks aliasing effects.
*/
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500");
static IIO_CONST_ATTR(in_anglvel_scale_available,
"0.000133090 0.000266181 0.000532362 0.001064724");

View File

@@ -175,7 +175,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
if (kfifo_len(&st->timestamps) >
fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR)
goto flush_fifo;
while (fifo_count >= bytes_per_datum) {
do {
result = regmap_bulk_read(st->map, st->reg->fifo_r_w,
data, bytes_per_datum);
if (result)
@@ -194,7 +194,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
timestamp);
fifo_count -= bytes_per_datum;
}
} while (fifo_count >= bytes_per_datum);
end_session:
mutex_unlock(&st->lock);

View File

@@ -409,6 +409,14 @@ config TSL2583
Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices.
Access ALS data via iio, sysfs.
config TSL2772
tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors"
depends on I2C
help
Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672,
tmd2672, tsl2772, tmd2772 devices.
Provides iio_events and direct access via sysfs.
config TSL4531
tristate "TAOS TSL4531 ambient light sensors"
depends on I2C

View File

@@ -40,6 +40,7 @@ obj-$(CONFIG_ST_UVIS25_SPI) += st_uvis25_spi.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL2583) += tsl2583.o
obj-$(CONFIG_TSL2772) += tsl2772.o
obj-$(CONFIG_TSL4531) += tsl4531.o
obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o

View File

@@ -600,7 +600,7 @@ done:
static IIO_CONST_ATTR(in_illuminance_calibscale_available, "1 8 16 111");
static IIO_CONST_ATTR(in_illuminance_integration_time_available,
"0.000050 0.000100 0.000150 0.000200 0.000250 0.000300 0.000350 0.000400 0.000450 0.000500 0.000550 0.000600 0.000650");
"0.050 0.100 0.150 0.200 0.250 0.300 0.350 0.400 0.450 0.500 0.550 0.600 0.650");
static IIO_DEVICE_ATTR_RW(in_illuminance_input_target, 0);
static IIO_DEVICE_ATTR_WO(in_illuminance_calibrate, 0);
static IIO_DEVICE_ATTR_RW(in_illuminance_lux_table, 0);

View File

@@ -26,6 +26,7 @@
#define MAG3110_OUT_Y 0x03
#define MAG3110_OUT_Z 0x05
#define MAG3110_WHO_AM_I 0x07
#define MAG3110_SYSMOD 0x08
#define MAG3110_OFF_X 0x09 /* MSB first */
#define MAG3110_OFF_Y 0x0b
#define MAG3110_OFF_Z 0x0d
@@ -39,6 +40,8 @@
#define MAG3110_CTRL_DR_SHIFT 5
#define MAG3110_CTRL_DR_DEFAULT 0
#define MAG3110_SYSMOD_MODE_MASK GENMASK(1, 0)
#define MAG3110_CTRL_TM BIT(1) /* trigger single measurement */
#define MAG3110_CTRL_AC BIT(0) /* continuous measurements */
@@ -52,17 +55,20 @@ struct mag3110_data {
struct i2c_client *client;
struct mutex lock;
u8 ctrl_reg1;
int sleep_val;
};
static int mag3110_request(struct mag3110_data *data)
{
int ret, tries = 150;
/* trigger measurement */
ret = i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1,
data->ctrl_reg1 | MAG3110_CTRL_TM);
if (ret < 0)
return ret;
if ((data->ctrl_reg1 & MAG3110_CTRL_AC) == 0) {
/* trigger measurement */
ret = i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1,
data->ctrl_reg1 | MAG3110_CTRL_TM);
if (ret < 0)
return ret;
}
while (tries-- > 0) {
ret = i2c_smbus_read_byte_data(data->client, MAG3110_STATUS);
@@ -71,7 +77,11 @@ static int mag3110_request(struct mag3110_data *data)
/* wait for data ready */
if ((ret & MAG3110_STATUS_DRDY) == MAG3110_STATUS_DRDY)
break;
msleep(20);
if (data->sleep_val <= 20)
usleep_range(data->sleep_val * 250, data->sleep_val * 500);
else
msleep(20);
}
if (tries < 0) {
@@ -144,6 +154,117 @@ static int mag3110_get_samp_freq_index(struct mag3110_data *data,
val2);
}
static int mag3110_calculate_sleep(struct mag3110_data *data)
{
int ret, i = data->ctrl_reg1 >> MAG3110_CTRL_DR_SHIFT;
if (mag3110_samp_freq[i][0] > 0)
ret = 1000 / mag3110_samp_freq[i][0];
else
ret = 1000;
return ret == 0 ? 1 : ret;
}
static int mag3110_standby(struct mag3110_data *data)
{
return i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1,
data->ctrl_reg1 & ~MAG3110_CTRL_AC);
}
static int mag3110_wait_standby(struct mag3110_data *data)
{
int ret, tries = 30;
/*
* Takes up to 1/ODR to come out of active mode into stby
* Longest expected period is 12.5seconds.
* We'll sleep for 500ms between checks
*/
while (tries-- > 0) {
ret = i2c_smbus_read_byte_data(data->client, MAG3110_SYSMOD);
if (ret < 0) {
dev_err(&data->client->dev, "i2c error\n");
return ret;
}
/* wait for standby */
if ((ret & MAG3110_SYSMOD_MODE_MASK) == 0)
break;
msleep_interruptible(500);
}
if (tries < 0) {
dev_err(&data->client->dev, "device not entering standby mode\n");
return -EIO;
}
return 0;
}
static int mag3110_active(struct mag3110_data *data)
{
return i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1,
data->ctrl_reg1);
}
/* returns >0 if active, 0 if in standby and <0 on error */
static int mag3110_is_active(struct mag3110_data *data)
{
int reg;
reg = i2c_smbus_read_byte_data(data->client, MAG3110_CTRL_REG1);
if (reg < 0)
return reg;
return reg & MAG3110_CTRL_AC;
}
static int mag3110_change_config(struct mag3110_data *data, u8 reg, u8 val)
{
int ret;
int is_active;
mutex_lock(&data->lock);
is_active = mag3110_is_active(data);
if (is_active < 0) {
ret = is_active;
goto fail;
}
/* config can only be changed when in standby */
if (is_active > 0) {
ret = mag3110_standby(data);
if (ret < 0)
goto fail;
}
/*
* After coming out of active we must wait for the part
* to transition to STBY. This can take up to 1 /ODR to occur
*/
ret = mag3110_wait_standby(data);
if (ret < 0)
goto fail;
ret = i2c_smbus_write_byte_data(data->client, reg, val);
if (ret < 0)
goto fail;
if (is_active > 0) {
ret = mag3110_active(data);
if (ret < 0)
goto fail;
}
ret = 0;
fail:
mutex_unlock(&data->lock);
return ret;
}
static int mag3110_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -235,11 +356,15 @@ static int mag3110_write_raw(struct iio_dev *indio_dev,
ret = -EINVAL;
break;
}
data->ctrl_reg1 &= ~MAG3110_CTRL_DR_MASK;
data->ctrl_reg1 &= 0xff & ~MAG3110_CTRL_DR_MASK
& ~MAG3110_CTRL_AC;
data->ctrl_reg1 |= rate << MAG3110_CTRL_DR_SHIFT;
ret = i2c_smbus_write_byte_data(data->client,
MAG3110_CTRL_REG1, data->ctrl_reg1);
data->sleep_val = mag3110_calculate_sleep(data);
if (data->sleep_val < 40)
data->ctrl_reg1 |= MAG3110_CTRL_AC;
ret = mag3110_change_config(data, MAG3110_CTRL_REG1,
data->ctrl_reg1);
break;
case IIO_CHAN_INFO_CALIBBIAS:
if (val < -10000 || val > 10000) {
@@ -337,12 +462,6 @@ static const struct iio_info mag3110_info = {
static const unsigned long mag3110_scan_masks[] = {0x7, 0xf, 0};
static int mag3110_standby(struct mag3110_data *data)
{
return i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1,
data->ctrl_reg1 & ~MAG3110_CTRL_AC);
}
static int mag3110_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -374,8 +493,11 @@ static int mag3110_probe(struct i2c_client *client,
indio_dev->available_scan_masks = mag3110_scan_masks;
data->ctrl_reg1 = MAG3110_CTRL_DR_DEFAULT << MAG3110_CTRL_DR_SHIFT;
ret = i2c_smbus_write_byte_data(client, MAG3110_CTRL_REG1,
data->ctrl_reg1);
data->sleep_val = mag3110_calculate_sleep(data);
if (data->sleep_val < 40)
data->ctrl_reg1 |= MAG3110_CTRL_AC;
ret = mag3110_change_config(data, MAG3110_CTRL_REG1, data->ctrl_reg1);
if (ret < 0)
return ret;

View File

@@ -411,12 +411,14 @@ static int lmp91000_remove(struct i2c_client *client)
static const struct of_device_id lmp91000_of_match[] = {
{ .compatible = "ti,lmp91000", },
{ .compatible = "ti,lmp91002", },
{ },
};
MODULE_DEVICE_TABLE(of, lmp91000_of_match);
static const struct i2c_device_id lmp91000_id[] = {
{ "lmp91000", 0 },
{ "lmp91002", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, lmp91000_id);

View File

@@ -0,0 +1,17 @@
#
# Resolver/Synchro drivers
#
menu "Resolver to digital converters"
config AD2S1200
tristate "Analog Devices ad2s1200/ad2s1205 driver"
depends on SPI
depends on GPIOLIB || COMPILE_TEST
help
Say yes here to build support for Analog Devices spi resolver
to digital converters, ad2s1200 and ad2s1205, provides direct access
via sysfs.
To compile this driver as a module, choose M here: the
module will be called ad2s1200.
endmenu

View File

@@ -0,0 +1,5 @@
#
# Makefile for Resolver/Synchro drivers
#
obj-$(CONFIG_AD2S1200) += ad2s1200.o

View File

@@ -2,18 +2,19 @@
* ad2s1200.c simple support for the ADI Resolver to Digital Converters:
* AD2S1200/1205
*
* Copyright (c) 2018-2018 David Veenstra <davidjulianveenstra@gmail.com>
* Copyright (c) 2010-2010 Analog Devices Inc.
*
* 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/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spi/spi.h>
@@ -25,19 +26,24 @@
#define DRV_NAME "ad2s1200"
/* input pin sample and rdvel is controlled by driver */
#define AD2S1200_PN 2
/* input clock on serial interface */
#define AD2S1200_HZ 8192000
/* clock period in nano second */
#define AD2S1200_TSCLK (1000000000 / AD2S1200_HZ)
/**
* struct ad2s1200_state - driver instance specific data.
* @lock: protects both the GPIO pins and the rx buffer.
* @sdev: spi device.
* @sample: GPIO pin SAMPLE.
* @rdvel: GPIO pin RDVEL.
* @rx: buffer for spi transfers.
*/
struct ad2s1200_state {
struct mutex lock;
struct spi_device *sdev;
int sample;
int rdvel;
struct gpio_desc *sample;
struct gpio_desc *rdvel;
__be16 rx ____cacheline_aligned;
};
@@ -48,39 +54,62 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev,
long m)
{
struct ad2s1200_state *st = iio_priv(indio_dev);
int ret = 0;
int ret;
mutex_lock(&st->lock);
gpio_set_value(st->sample, 0);
switch (m) {
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL:
/* 2 * Pi / (2^12 - 1) ~= 0.001534355 */
*val = 0;
*val2 = 1534355;
return IIO_VAL_INT_PLUS_NANO;
case IIO_ANGL_VEL:
/* 2 * Pi ~= 6.283185 */
*val = 6;
*val2 = 283185;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
break;
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
gpiod_set_value(st->sample, 0);
/* delay (6 * AD2S1200_TSCLK + 20) nano seconds */
udelay(1);
gpio_set_value(st->sample, 1);
gpio_set_value(st->rdvel, !!(chan->type == IIO_ANGL));
/* delay (6 * AD2S1200_TSCLK + 20) nano seconds */
udelay(1);
gpiod_set_value(st->sample, 1);
gpiod_set_value(st->rdvel, !!(chan->type == IIO_ANGL));
ret = spi_read(st->sdev, &st->rx, 2);
if (ret < 0) {
ret = spi_read(st->sdev, &st->rx, 2);
if (ret < 0) {
mutex_unlock(&st->lock);
return ret;
}
switch (chan->type) {
case IIO_ANGL:
*val = be16_to_cpup(&st->rx) >> 4;
break;
case IIO_ANGL_VEL:
*val = sign_extend32(be16_to_cpup(&st->rx) >> 4, 11);
break;
default:
mutex_unlock(&st->lock);
return -EINVAL;
}
/* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */
udelay(1);
mutex_unlock(&st->lock);
return ret;
}
switch (chan->type) {
case IIO_ANGL:
*val = be16_to_cpup(&st->rx) >> 4;
break;
case IIO_ANGL_VEL:
*val = sign_extend32(be16_to_cpup(&st->rx) >> 4, 11);
break;
return IIO_VAL_INT;
default:
mutex_unlock(&st->lock);
return -EINVAL;
break;
}
/* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */
udelay(1);
mutex_unlock(&st->lock);
return IIO_VAL_INT;
return -EINVAL;
}
static const struct iio_chan_spec ad2s1200_channels[] = {
@@ -89,11 +118,13 @@ static const struct iio_chan_spec ad2s1200_channels[] = {
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_ANGL_VEL,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
}
};
@@ -103,20 +134,9 @@ static const struct iio_info ad2s1200_info = {
static int ad2s1200_probe(struct spi_device *spi)
{
unsigned short *pins = spi->dev.platform_data;
struct ad2s1200_state *st;
struct iio_dev *indio_dev;
int pn, ret = 0;
for (pn = 0; pn < AD2S1200_PN; pn++) {
ret = devm_gpio_request_one(&spi->dev, pins[pn], GPIOF_DIR_OUT,
DRV_NAME);
if (ret) {
dev_err(&spi->dev, "request gpio pin %d failed\n",
pins[pn]);
return ret;
}
}
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
@@ -126,8 +146,20 @@ static int ad2s1200_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
mutex_init(&st->lock);
st->sdev = spi;
st->sample = pins[0];
st->rdvel = pins[1];
st->sample = devm_gpiod_get(&spi->dev, "adi,sample", GPIOD_OUT_LOW);
if (IS_ERR(st->sample)) {
dev_err(&spi->dev, "Failed to claim SAMPLE gpio: err=%ld\n",
PTR_ERR(st->sample));
return PTR_ERR(st->sample);
}
st->rdvel = devm_gpiod_get(&spi->dev, "adi,rdvel", GPIOD_OUT_LOW);
if (IS_ERR(st->rdvel)) {
dev_err(&spi->dev, "Failed to claim RDVEL gpio: err=%ld\n",
PTR_ERR(st->rdvel));
return PTR_ERR(st->rdvel);
}
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ad2s1200_info;
@@ -136,17 +168,25 @@ static int ad2s1200_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(ad2s1200_channels);
indio_dev->name = spi_get_device_id(spi)->name;
ret = devm_iio_device_register(&spi->dev, indio_dev);
if (ret)
return ret;
spi->max_speed_hz = AD2S1200_HZ;
spi->mode = SPI_MODE_3;
spi_setup(spi);
ret = spi_setup(spi);
return 0;
if (ret < 0) {
dev_err(&spi->dev, "spi_setup failed!\n");
return ret;
}
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id ad2s1200_of_match[] = {
{ .compatible = "adi,ad2s1200", },
{ .compatible = "adi,ad2s1205", },
{ }
};
MODULE_DEVICE_TABLE(of, ad2s1200_of_match);
static const struct spi_device_id ad2s1200_id[] = {
{ "ad2s1200" },
{ "ad2s1205" },
@@ -157,12 +197,14 @@ MODULE_DEVICE_TABLE(spi, ad2s1200_id);
static struct spi_driver ad2s1200_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(ad2s1200_of_match),
},
.probe = ad2s1200_probe,
.id_table = ad2s1200_id,
};
module_spi_driver(ad2s1200_driver);
MODULE_AUTHOR("David Veenstra <davidjulianveenstra@gmail.com>");
MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver");
MODULE_LICENSE("GPL v2");

View File

@@ -11,7 +11,6 @@ source "drivers/staging/iio/cdc/Kconfig"
source "drivers/staging/iio/frequency/Kconfig"
source "drivers/staging/iio/gyro/Kconfig"
source "drivers/staging/iio/impedance-analyzer/Kconfig"
source "drivers/staging/iio/light/Kconfig"
source "drivers/staging/iio/meter/Kconfig"
source "drivers/staging/iio/resolver/Kconfig"

View File

@@ -10,6 +10,5 @@ obj-y += cdc/
obj-y += frequency/
obj-y += gyro/
obj-y += impedance-analyzer/
obj-y += light/
obj-y += meter/
obj-y += resolver/

View File

@@ -1,14 +0,0 @@
#
# Light sensors
#
menu "Light sensors"
config TSL2x7x
tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors"
depends on I2C
help
Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672,
tmd2672, tsl2772, tmd2772 devices.
Provides iio_events and direct access via sysfs.
endmenu

View File

@@ -1,5 +0,0 @@
#
# Makefile for industrial I/O Light sensors
#
obj-$(CONFIG_TSL2x7x) += tsl2x7x.o

View File

@@ -3,48 +3,6 @@
#
menu "Active energy metering IC"
config ADE7753
tristate "Analog Devices ADE7753/6 Single-Phase Multifunction Metering IC Driver"
depends on SPI
help
Say yes here to build support for Analog Devices ADE7753 Single-Phase Multifunction
Metering IC with di/dt Sensor Interface.
To compile this driver as a module, choose M here: the
module will be called ade7753.
config ADE7754
tristate "Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver"
depends on SPI
help
Say yes here to build support for Analog Devices ADE7754 Polyphase
Multifunction Energy Metering IC Driver.
To compile this driver as a module, choose M here: the
module will be called ade7754.
config ADE7758
tristate "Analog Devices ADE7758 Poly Phase Multifunction Energy Metering IC Driver"
depends on SPI
select IIO_TRIGGER if IIO_BUFFER
select IIO_KFIFO_BUF if IIO_BUFFER
help
Say yes here to build support for Analog Devices ADE7758 Polyphase
Multifunction Energy Metering IC with Per Phase Information Driver.
To compile this driver as a module, choose M here: the
module will be called ade7758.
config ADE7759
tristate "Analog Devices ADE7759 Active Energy Metering IC Driver"
depends on SPI
help
Say yes here to build support for Analog Devices ADE7758 Active Energy
Metering IC with di/dt Sensor Interface.
To compile this driver as a module, choose M here: the
module will be called ade7759.
config ADE7854
tristate "Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver"
depends on SPI || I2C

View File

@@ -3,14 +3,6 @@
# Makefile for metering ic drivers
#
obj-$(CONFIG_ADE7753) += ade7753.o
obj-$(CONFIG_ADE7754) += ade7754.o
ade7758-y := ade7758_core.o
ade7758-$(CONFIG_IIO_BUFFER) += ade7758_ring.o ade7758_trigger.o
obj-$(CONFIG_ADE7758) += ade7758.o
obj-$(CONFIG_ADE7759) += ade7759.o
obj-$(CONFIG_ADE7854) += ade7854.o
obj-$(CONFIG_ADE7854_I2C) += ade7854-i2c.o
obj-$(CONFIG_ADE7854_SPI) += ade7854-spi.o

View File

@@ -1,630 +0,0 @@
/*
* ADE7753 Single-Phase Multifunction Metering IC with di/dt Sensor Interface
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/spi/spi.h>
#include "meter.h"
#define ADE7753_WAVEFORM 0x01
#define ADE7753_AENERGY 0x02
#define ADE7753_RAENERGY 0x03
#define ADE7753_LAENERGY 0x04
#define ADE7753_VAENERGY 0x05
#define ADE7753_RVAENERGY 0x06
#define ADE7753_LVAENERGY 0x07
#define ADE7753_LVARENERGY 0x08
#define ADE7753_MODE 0x09
#define ADE7753_IRQEN 0x0A
#define ADE7753_STATUS 0x0B
#define ADE7753_RSTSTATUS 0x0C
#define ADE7753_CH1OS 0x0D
#define ADE7753_CH2OS 0x0E
#define ADE7753_GAIN 0x0F
#define ADE7753_PHCAL 0x10
#define ADE7753_APOS 0x11
#define ADE7753_WGAIN 0x12
#define ADE7753_WDIV 0x13
#define ADE7753_CFNUM 0x14
#define ADE7753_CFDEN 0x15
#define ADE7753_IRMS 0x16
#define ADE7753_VRMS 0x17
#define ADE7753_IRMSOS 0x18
#define ADE7753_VRMSOS 0x19
#define ADE7753_VAGAIN 0x1A
#define ADE7753_VADIV 0x1B
#define ADE7753_LINECYC 0x1C
#define ADE7753_ZXTOUT 0x1D
#define ADE7753_SAGCYC 0x1E
#define ADE7753_SAGLVL 0x1F
#define ADE7753_IPKLVL 0x20
#define ADE7753_VPKLVL 0x21
#define ADE7753_IPEAK 0x22
#define ADE7753_RSTIPEAK 0x23
#define ADE7753_VPEAK 0x24
#define ADE7753_RSTVPEAK 0x25
#define ADE7753_TEMP 0x26
#define ADE7753_PERIOD 0x27
#define ADE7753_TMODE 0x3D
#define ADE7753_CHKSUM 0x3E
#define ADE7753_DIEREV 0x3F
#define ADE7753_READ_REG(a) a
#define ADE7753_WRITE_REG(a) ((a) | 0x80)
#define ADE7753_MAX_TX 4
#define ADE7753_MAX_RX 4
#define ADE7753_STARTUP_DELAY 1000
#define ADE7753_SPI_SLOW (u32)(300 * 1000)
#define ADE7753_SPI_BURST (u32)(1000 * 1000)
#define ADE7753_SPI_FAST (u32)(2000 * 1000)
/**
* struct ade7753_state - device instance specific data
* @us: actual spi_device
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx, rx and write frequency
**/
struct ade7753_state {
struct spi_device *us;
struct mutex buf_lock;
u8 tx[ADE7753_MAX_TX] ____cacheline_aligned;
u8 rx[ADE7753_MAX_RX];
};
static int ade7753_spi_write_reg_8(struct device *dev,
u8 reg_address,
u8 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7753_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
static int __ade7753_spi_write_reg_16(struct device *dev, u8 reg_address,
u16 value)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
st->tx[0] = ADE7753_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
return spi_write(st->us, st->tx, 3);
}
static int ade7753_spi_write_reg_16(struct device *dev, u8 reg_address,
u16 value)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
ret = __ade7753_spi_write_reg_16(dev, reg_address, value);
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7753_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
ssize_t ret;
ret = spi_w8r8(st->us, ADE7753_READ_REG(reg_address));
if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
reg_address);
return ret;
}
*val = ret;
return 0;
}
static int ade7753_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
ssize_t ret;
ret = spi_w8r16be(st->us, ADE7753_READ_REG(reg_address));
if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
reg_address);
return ret;
}
*val = ret;
return 0;
}
static int ade7753_spi_read_reg_24(struct device *dev,
u8 reg_address,
u32 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 1,
}, {
.rx_buf = st->tx,
.bits_per_word = 8,
.len = 3,
}
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7753_READ_REG(reg_address);
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
reg_address);
goto error_ret;
}
*val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static ssize_t ade7753_read_8bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u8 val;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7753_spi_read_reg_8(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7753_read_16bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u16 val;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7753_spi_read_reg_16(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7753_read_24bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u32 val;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7753_spi_read_reg_24(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7753_write_8bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u8 val;
ret = kstrtou8(buf, 10, &val);
if (ret)
goto error_ret;
ret = ade7753_spi_write_reg_8(dev, this_attr->address, val);
error_ret:
return ret ? ret : len;
}
static ssize_t ade7753_write_16bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u16 val;
ret = kstrtou16(buf, 10, &val);
if (ret)
goto error_ret;
ret = ade7753_spi_write_reg_16(dev, this_attr->address, val);
error_ret:
return ret ? ret : len;
}
static int ade7753_reset(struct device *dev)
{
u16 val;
int ret;
ret = ade7753_spi_read_reg_16(dev, ADE7753_MODE, &val);
if (ret)
return ret;
val |= BIT(6); /* Software Chip Reset */
return ade7753_spi_write_reg_16(dev, ADE7753_MODE, val);
}
static IIO_DEV_ATTR_AENERGY(ade7753_read_24bit, ADE7753_AENERGY);
static IIO_DEV_ATTR_LAENERGY(ade7753_read_24bit, ADE7753_LAENERGY);
static IIO_DEV_ATTR_VAENERGY(ade7753_read_24bit, ADE7753_VAENERGY);
static IIO_DEV_ATTR_LVAENERGY(ade7753_read_24bit, ADE7753_LVAENERGY);
static IIO_DEV_ATTR_CFDEN(0644,
ade7753_read_16bit,
ade7753_write_16bit,
ADE7753_CFDEN);
static IIO_DEV_ATTR_CFNUM(0644,
ade7753_read_8bit,
ade7753_write_8bit,
ADE7753_CFNUM);
static IIO_DEV_ATTR_CHKSUM(ade7753_read_8bit, ADE7753_CHKSUM);
static IIO_DEV_ATTR_PHCAL(0644,
ade7753_read_16bit,
ade7753_write_16bit,
ADE7753_PHCAL);
static IIO_DEV_ATTR_APOS(0644,
ade7753_read_16bit,
ade7753_write_16bit,
ADE7753_APOS);
static IIO_DEV_ATTR_SAGCYC(0644,
ade7753_read_8bit,
ade7753_write_8bit,
ADE7753_SAGCYC);
static IIO_DEV_ATTR_SAGLVL(0644,
ade7753_read_8bit,
ade7753_write_8bit,
ADE7753_SAGLVL);
static IIO_DEV_ATTR_LINECYC(0644,
ade7753_read_8bit,
ade7753_write_8bit,
ADE7753_LINECYC);
static IIO_DEV_ATTR_WDIV(0644,
ade7753_read_8bit,
ade7753_write_8bit,
ADE7753_WDIV);
static IIO_DEV_ATTR_IRMS(0644,
ade7753_read_24bit,
NULL,
ADE7753_IRMS);
static IIO_DEV_ATTR_VRMS(0444,
ade7753_read_24bit,
NULL,
ADE7753_VRMS);
static IIO_DEV_ATTR_IRMSOS(0644,
ade7753_read_16bit,
ade7753_write_16bit,
ADE7753_IRMSOS);
static IIO_DEV_ATTR_VRMSOS(0644,
ade7753_read_16bit,
ade7753_write_16bit,
ADE7753_VRMSOS);
static IIO_DEV_ATTR_WGAIN(0644,
ade7753_read_16bit,
ade7753_write_16bit,
ADE7753_WGAIN);
static IIO_DEV_ATTR_VAGAIN(0644,
ade7753_read_16bit,
ade7753_write_16bit,
ADE7753_VAGAIN);
static IIO_DEV_ATTR_PGA_GAIN(0644,
ade7753_read_16bit,
ade7753_write_16bit,
ADE7753_GAIN);
static IIO_DEV_ATTR_IPKLVL(0644,
ade7753_read_8bit,
ade7753_write_8bit,
ADE7753_IPKLVL);
static IIO_DEV_ATTR_VPKLVL(0644,
ade7753_read_8bit,
ade7753_write_8bit,
ADE7753_VPKLVL);
static IIO_DEV_ATTR_IPEAK(0444,
ade7753_read_24bit,
NULL,
ADE7753_IPEAK);
static IIO_DEV_ATTR_VPEAK(0444,
ade7753_read_24bit,
NULL,
ADE7753_VPEAK);
static IIO_DEV_ATTR_VPERIOD(0444,
ade7753_read_16bit,
NULL,
ADE7753_PERIOD);
static IIO_DEVICE_ATTR(choff_1, 0644,
ade7753_read_8bit,
ade7753_write_8bit,
ADE7753_CH1OS);
static IIO_DEVICE_ATTR(choff_2, 0644,
ade7753_read_8bit,
ade7753_write_8bit,
ADE7753_CH2OS);
static int ade7753_set_irq(struct device *dev, bool enable)
{
int ret;
u8 irqen;
ret = ade7753_spi_read_reg_8(dev, ADE7753_IRQEN, &irqen);
if (ret)
goto error_ret;
if (enable)
irqen |= BIT(3); /* Enables an interrupt when a data is
* present in the waveform register
*/
else
irqen &= ~BIT(3);
ret = ade7753_spi_write_reg_8(dev, ADE7753_IRQEN, irqen);
error_ret:
return ret;
}
/* Power down the device */
static int ade7753_stop_device(struct device *dev)
{
u16 val;
int ret;
ret = ade7753_spi_read_reg_16(dev, ADE7753_MODE, &val);
if (ret)
return ret;
val |= BIT(4); /* AD converters can be turned off */
return ade7753_spi_write_reg_16(dev, ADE7753_MODE, val);
}
static int ade7753_initial_setup(struct iio_dev *indio_dev)
{
int ret;
struct device *dev = &indio_dev->dev;
struct ade7753_state *st = iio_priv(indio_dev);
/* use low spi speed for init */
st->us->mode = SPI_MODE_3;
spi_setup(st->us);
/* Disable IRQ */
ret = ade7753_set_irq(dev, false);
if (ret) {
dev_err(dev, "disable irq failed");
goto err_ret;
}
ade7753_reset(dev);
usleep_range(ADE7753_STARTUP_DELAY, ADE7753_STARTUP_DELAY + 100);
err_ret:
return ret;
}
static ssize_t ade7753_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u16 t;
int sps;
ret = ade7753_spi_read_reg_16(dev, ADE7753_MODE, &t);
if (ret)
return ret;
t = (t >> 11) & 0x3;
sps = 27900 / (1 + t);
return sprintf(buf, "%d\n", sps);
}
static ssize_t ade7753_write_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
u16 val;
int ret;
u16 reg, t;
ret = kstrtou16(buf, 10, &val);
if (ret)
return ret;
if (!val)
return -EINVAL;
mutex_lock(&st->buf_lock);
t = 27900 / val;
if (t > 0)
t--;
if (t > 1)
st->us->max_speed_hz = ADE7753_SPI_SLOW;
else
st->us->max_speed_hz = ADE7753_SPI_FAST;
ret = ade7753_spi_read_reg_16(dev, ADE7753_MODE, &reg);
if (ret)
goto out;
reg &= ~(3 << 11);
reg |= t << 11;
ret = __ade7753_spi_write_reg_16(dev, ADE7753_MODE, reg);
out:
mutex_unlock(&st->buf_lock);
return ret ? ret : len;
}
static IIO_DEV_ATTR_TEMP_RAW(ade7753_read_8bit);
static IIO_CONST_ATTR(in_temp_offset, "-25 C");
static IIO_CONST_ATTR(in_temp_scale, "0.67 C");
static IIO_DEV_ATTR_SAMP_FREQ(0644,
ade7753_read_frequency,
ade7753_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
static struct attribute *ade7753_attributes[] = {
&iio_dev_attr_in_temp_raw.dev_attr.attr,
&iio_const_attr_in_temp_offset.dev_attr.attr,
&iio_const_attr_in_temp_scale.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_phcal.dev_attr.attr,
&iio_dev_attr_cfden.dev_attr.attr,
&iio_dev_attr_aenergy.dev_attr.attr,
&iio_dev_attr_laenergy.dev_attr.attr,
&iio_dev_attr_vaenergy.dev_attr.attr,
&iio_dev_attr_lvaenergy.dev_attr.attr,
&iio_dev_attr_cfnum.dev_attr.attr,
&iio_dev_attr_apos.dev_attr.attr,
&iio_dev_attr_sagcyc.dev_attr.attr,
&iio_dev_attr_saglvl.dev_attr.attr,
&iio_dev_attr_linecyc.dev_attr.attr,
&iio_dev_attr_chksum.dev_attr.attr,
&iio_dev_attr_pga_gain.dev_attr.attr,
&iio_dev_attr_wgain.dev_attr.attr,
&iio_dev_attr_choff_1.dev_attr.attr,
&iio_dev_attr_choff_2.dev_attr.attr,
&iio_dev_attr_wdiv.dev_attr.attr,
&iio_dev_attr_irms.dev_attr.attr,
&iio_dev_attr_vrms.dev_attr.attr,
&iio_dev_attr_irmsos.dev_attr.attr,
&iio_dev_attr_vrmsos.dev_attr.attr,
&iio_dev_attr_vagain.dev_attr.attr,
&iio_dev_attr_ipklvl.dev_attr.attr,
&iio_dev_attr_vpklvl.dev_attr.attr,
&iio_dev_attr_ipeak.dev_attr.attr,
&iio_dev_attr_vpeak.dev_attr.attr,
&iio_dev_attr_vperiod.dev_attr.attr,
NULL,
};
static const struct attribute_group ade7753_attribute_group = {
.attrs = ade7753_attributes,
};
static const struct iio_info ade7753_info = {
.attrs = &ade7753_attribute_group,
};
static int ade7753_probe(struct spi_device *spi)
{
int ret;
struct ade7753_state *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ade7753_info;
indio_dev->modes = INDIO_DIRECT_MODE;
/* Get the device into a sane initial state */
ret = ade7753_initial_setup(indio_dev);
if (ret)
return ret;
return iio_device_register(indio_dev);
}
static int ade7753_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
ade7753_stop_device(&indio_dev->dev);
return 0;
}
static struct spi_driver ade7753_driver = {
.driver = {
.name = "ade7753",
},
.probe = ade7753_probe,
.remove = ade7753_remove,
};
module_spi_driver(ade7753_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADE7753/6 Single-Phase Multifunction Meter");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:ade7753");

View File

@@ -1,664 +0,0 @@
/*
* ADE7754 Polyphase Multifunction Energy Metering IC Driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "meter.h"
#define ADE7754_AENERGY 0x01
#define ADE7754_RAENERGY 0x02
#define ADE7754_LAENERGY 0x03
#define ADE7754_VAENERGY 0x04
#define ADE7754_RVAENERGY 0x05
#define ADE7754_LVAENERGY 0x06
#define ADE7754_PERIOD 0x07
#define ADE7754_TEMP 0x08
#define ADE7754_WFORM 0x09
#define ADE7754_OPMODE 0x0A
#define ADE7754_MMODE 0x0B
#define ADE7754_WAVMODE 0x0C
#define ADE7754_WATMODE 0x0D
#define ADE7754_VAMODE 0x0E
#define ADE7754_IRQEN 0x0F
#define ADE7754_STATUS 0x10
#define ADE7754_RSTATUS 0x11
#define ADE7754_ZXTOUT 0x12
#define ADE7754_LINCYC 0x13
#define ADE7754_SAGCYC 0x14
#define ADE7754_SAGLVL 0x15
#define ADE7754_VPEAK 0x16
#define ADE7754_IPEAK 0x17
#define ADE7754_GAIN 0x18
#define ADE7754_AWG 0x19
#define ADE7754_BWG 0x1A
#define ADE7754_CWG 0x1B
#define ADE7754_AVAG 0x1C
#define ADE7754_BVAG 0x1D
#define ADE7754_CVAG 0x1E
#define ADE7754_APHCAL 0x1F
#define ADE7754_BPHCAL 0x20
#define ADE7754_CPHCAL 0x21
#define ADE7754_AAPOS 0x22
#define ADE7754_BAPOS 0x23
#define ADE7754_CAPOS 0x24
#define ADE7754_CFNUM 0x25
#define ADE7754_CFDEN 0x26
#define ADE7754_WDIV 0x27
#define ADE7754_VADIV 0x28
#define ADE7754_AIRMS 0x29
#define ADE7754_BIRMS 0x2A
#define ADE7754_CIRMS 0x2B
#define ADE7754_AVRMS 0x2C
#define ADE7754_BVRMS 0x2D
#define ADE7754_CVRMS 0x2E
#define ADE7754_AIRMSOS 0x2F
#define ADE7754_BIRMSOS 0x30
#define ADE7754_CIRMSOS 0x31
#define ADE7754_AVRMSOS 0x32
#define ADE7754_BVRMSOS 0x33
#define ADE7754_CVRMSOS 0x34
#define ADE7754_AAPGAIN 0x35
#define ADE7754_BAPGAIN 0x36
#define ADE7754_CAPGAIN 0x37
#define ADE7754_AVGAIN 0x38
#define ADE7754_BVGAIN 0x39
#define ADE7754_CVGAIN 0x3A
#define ADE7754_CHKSUM 0x3E
#define ADE7754_VERSION 0x3F
#define ADE7754_READ_REG(a) a
#define ADE7754_WRITE_REG(a) ((a) | 0x80)
#define ADE7754_MAX_TX 4
#define ADE7754_MAX_RX 4
#define ADE7754_STARTUP_DELAY 1000
#define ADE7754_SPI_SLOW (u32)(300 * 1000)
#define ADE7754_SPI_BURST (u32)(1000 * 1000)
#define ADE7754_SPI_FAST (u32)(2000 * 1000)
/**
* struct ade7754_state - device instance specific data
* @us: actual spi_device
* @buf_lock: mutex to protect tx, rx and write frequency
* @tx: transmit buffer
* @rx: receive buffer
**/
struct ade7754_state {
struct spi_device *us;
struct mutex buf_lock;
u8 tx[ADE7754_MAX_TX] ____cacheline_aligned;
u8 rx[ADE7754_MAX_RX];
};
/* Unlocked version of ade7754_spi_write_reg_8 function */
static int __ade7754_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
st->tx[0] = ADE7754_WRITE_REG(reg_address);
st->tx[1] = val;
return spi_write(st->us, st->tx, 2);
}
static int ade7754_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
ret = __ade7754_spi_write_reg_8(dev, reg_address, val);
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7754_spi_write_reg_16(struct device *dev,
u8 reg_address, u16 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7754_WRITE_REG(reg_address);
st->tx[1] = (val >> 8) & 0xFF;
st->tx[2] = val & 0xFF;
ret = spi_write(st->us, st->tx, 3);
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7754_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
int ret;
ret = spi_w8r8(st->us, ADE7754_READ_REG(reg_address));
if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
reg_address);
return ret;
}
*val = ret;
return 0;
}
static int ade7754_spi_read_reg_16(struct device *dev,
u8 reg_address, u16 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
int ret;
ret = spi_w8r16be(st->us, ADE7754_READ_REG(reg_address));
if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
reg_address);
return ret;
}
*val = ret;
return 0;
}
static int ade7754_spi_read_reg_24(struct device *dev,
u8 reg_address, u32 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 4,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7754_READ_REG(reg_address);
st->tx[1] = 0;
st->tx[2] = 0;
st->tx[3] = 0;
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
reg_address);
goto error_ret;
}
*val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static ssize_t ade7754_read_8bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u8 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7754_spi_read_reg_8(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7754_read_16bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u16 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7754_spi_read_reg_16(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7754_read_24bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u32 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7754_spi_read_reg_24(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val & 0xFFFFFF);
}
static ssize_t ade7754_write_8bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u8 val;
ret = kstrtou8(buf, 10, &val);
if (ret)
goto error_ret;
ret = ade7754_spi_write_reg_8(dev, this_attr->address, val);
error_ret:
return ret ? ret : len;
}
static ssize_t ade7754_write_16bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u16 val;
ret = kstrtou16(buf, 10, &val);
if (ret)
goto error_ret;
ret = ade7754_spi_write_reg_16(dev, this_attr->address, val);
error_ret:
return ret ? ret : len;
}
static int ade7754_reset(struct device *dev)
{
int ret;
u8 val;
ret = ade7754_spi_read_reg_8(dev, ADE7754_OPMODE, &val);
if (ret < 0)
return ret;
val |= BIT(6); /* Software Chip Reset */
return ade7754_spi_write_reg_8(dev, ADE7754_OPMODE, val);
}
static IIO_DEV_ATTR_AENERGY(ade7754_read_24bit, ADE7754_AENERGY);
static IIO_DEV_ATTR_LAENERGY(ade7754_read_24bit, ADE7754_LAENERGY);
static IIO_DEV_ATTR_VAENERGY(ade7754_read_24bit, ADE7754_VAENERGY);
static IIO_DEV_ATTR_LVAENERGY(ade7754_read_24bit, ADE7754_LVAENERGY);
static IIO_DEV_ATTR_VPEAK(0644,
ade7754_read_8bit,
ade7754_write_8bit,
ADE7754_VPEAK);
static IIO_DEV_ATTR_IPEAK(0644,
ade7754_read_8bit,
ade7754_write_8bit,
ADE7754_VPEAK);
static IIO_DEV_ATTR_APHCAL(0644,
ade7754_read_8bit,
ade7754_write_8bit,
ADE7754_APHCAL);
static IIO_DEV_ATTR_BPHCAL(0644,
ade7754_read_8bit,
ade7754_write_8bit,
ADE7754_BPHCAL);
static IIO_DEV_ATTR_CPHCAL(0644,
ade7754_read_8bit,
ade7754_write_8bit,
ADE7754_CPHCAL);
static IIO_DEV_ATTR_AAPOS(0644,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_AAPOS);
static IIO_DEV_ATTR_BAPOS(0644,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_BAPOS);
static IIO_DEV_ATTR_CAPOS(0644,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_CAPOS);
static IIO_DEV_ATTR_WDIV(0644,
ade7754_read_8bit,
ade7754_write_8bit,
ADE7754_WDIV);
static IIO_DEV_ATTR_VADIV(0644,
ade7754_read_8bit,
ade7754_write_8bit,
ADE7754_VADIV);
static IIO_DEV_ATTR_CFNUM(0644,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_CFNUM);
static IIO_DEV_ATTR_CFDEN(0644,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_CFDEN);
static IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(0644,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_AAPGAIN);
static IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(0644,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_BAPGAIN);
static IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(0644,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_CAPGAIN);
static IIO_DEV_ATTR_AIRMS(0444,
ade7754_read_24bit,
NULL,
ADE7754_AIRMS);
static IIO_DEV_ATTR_BIRMS(0444,
ade7754_read_24bit,
NULL,
ADE7754_BIRMS);
static IIO_DEV_ATTR_CIRMS(0444,
ade7754_read_24bit,
NULL,
ADE7754_CIRMS);
static IIO_DEV_ATTR_AVRMS(0444,
ade7754_read_24bit,
NULL,
ADE7754_AVRMS);
static IIO_DEV_ATTR_BVRMS(0444,
ade7754_read_24bit,
NULL,
ADE7754_BVRMS);
static IIO_DEV_ATTR_CVRMS(0444,
ade7754_read_24bit,
NULL,
ADE7754_CVRMS);
static IIO_DEV_ATTR_AIRMSOS(0444,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_AIRMSOS);
static IIO_DEV_ATTR_BIRMSOS(0444,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_BIRMSOS);
static IIO_DEV_ATTR_CIRMSOS(0444,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_CIRMSOS);
static IIO_DEV_ATTR_AVRMSOS(0444,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_AVRMSOS);
static IIO_DEV_ATTR_BVRMSOS(0444,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_BVRMSOS);
static IIO_DEV_ATTR_CVRMSOS(0444,
ade7754_read_16bit,
ade7754_write_16bit,
ADE7754_CVRMSOS);
static int ade7754_set_irq(struct device *dev, bool enable)
{
int ret;
u16 irqen;
ret = ade7754_spi_read_reg_16(dev, ADE7754_IRQEN, &irqen);
if (ret)
return ret;
if (enable)
irqen |= BIT(14); /* Enables an interrupt when a data is
* present in the waveform register
*/
else
irqen &= ~BIT(14);
return ade7754_spi_write_reg_16(dev, ADE7754_IRQEN, irqen);
}
/* Power down the device */
static int ade7754_stop_device(struct device *dev)
{
int ret;
u8 val;
ret = ade7754_spi_read_reg_8(dev, ADE7754_OPMODE, &val);
if (ret < 0) {
dev_err(dev, "unable to power down the device, error: %d",
ret);
return ret;
}
val |= 7 << 3; /* ADE7754 powered down */
return ade7754_spi_write_reg_8(dev, ADE7754_OPMODE, val);
}
static int ade7754_initial_setup(struct iio_dev *indio_dev)
{
int ret;
struct ade7754_state *st = iio_priv(indio_dev);
struct device *dev = &indio_dev->dev;
/* use low spi speed for init */
st->us->mode = SPI_MODE_3;
spi_setup(st->us);
/* Disable IRQ */
ret = ade7754_set_irq(dev, false);
if (ret) {
dev_err(dev, "disable irq failed");
goto err_ret;
}
ade7754_reset(dev);
usleep_range(ADE7754_STARTUP_DELAY, ADE7754_STARTUP_DELAY + 100);
err_ret:
return ret;
}
static ssize_t ade7754_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u8 t;
int sps;
ret = ade7754_spi_read_reg_8(dev, ADE7754_WAVMODE, &t);
if (ret)
return ret;
t = (t >> 3) & 0x3;
sps = 26000 / (1 + t);
return sprintf(buf, "%d\n", sps);
}
static ssize_t ade7754_write_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
u16 val;
int ret;
u8 reg, t;
ret = kstrtou16(buf, 10, &val);
if (ret)
return ret;
if (!val)
return -EINVAL;
mutex_lock(&st->buf_lock);
t = 26000 / val;
if (t > 0)
t--;
if (t > 1)
st->us->max_speed_hz = ADE7754_SPI_SLOW;
else
st->us->max_speed_hz = ADE7754_SPI_FAST;
ret = ade7754_spi_read_reg_8(dev, ADE7754_WAVMODE, &reg);
if (ret)
goto out;
reg &= ~(3 << 3);
reg |= t << 3;
ret = __ade7754_spi_write_reg_8(dev, ADE7754_WAVMODE, reg);
out:
mutex_unlock(&st->buf_lock);
return ret ? ret : len;
}
static IIO_DEV_ATTR_TEMP_RAW(ade7754_read_8bit);
static IIO_CONST_ATTR(in_temp_offset, "129 C");
static IIO_CONST_ATTR(in_temp_scale, "4 C");
static IIO_DEV_ATTR_SAMP_FREQ(0644,
ade7754_read_frequency,
ade7754_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000");
static struct attribute *ade7754_attributes[] = {
&iio_dev_attr_in_temp_raw.dev_attr.attr,
&iio_const_attr_in_temp_offset.dev_attr.attr,
&iio_const_attr_in_temp_scale.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_aenergy.dev_attr.attr,
&iio_dev_attr_laenergy.dev_attr.attr,
&iio_dev_attr_vaenergy.dev_attr.attr,
&iio_dev_attr_lvaenergy.dev_attr.attr,
&iio_dev_attr_vpeak.dev_attr.attr,
&iio_dev_attr_ipeak.dev_attr.attr,
&iio_dev_attr_aphcal.dev_attr.attr,
&iio_dev_attr_bphcal.dev_attr.attr,
&iio_dev_attr_cphcal.dev_attr.attr,
&iio_dev_attr_aapos.dev_attr.attr,
&iio_dev_attr_bapos.dev_attr.attr,
&iio_dev_attr_capos.dev_attr.attr,
&iio_dev_attr_wdiv.dev_attr.attr,
&iio_dev_attr_vadiv.dev_attr.attr,
&iio_dev_attr_cfnum.dev_attr.attr,
&iio_dev_attr_cfden.dev_attr.attr,
&iio_dev_attr_active_power_a_gain.dev_attr.attr,
&iio_dev_attr_active_power_b_gain.dev_attr.attr,
&iio_dev_attr_active_power_c_gain.dev_attr.attr,
&iio_dev_attr_airms.dev_attr.attr,
&iio_dev_attr_birms.dev_attr.attr,
&iio_dev_attr_cirms.dev_attr.attr,
&iio_dev_attr_avrms.dev_attr.attr,
&iio_dev_attr_bvrms.dev_attr.attr,
&iio_dev_attr_cvrms.dev_attr.attr,
&iio_dev_attr_airmsos.dev_attr.attr,
&iio_dev_attr_birmsos.dev_attr.attr,
&iio_dev_attr_cirmsos.dev_attr.attr,
&iio_dev_attr_avrmsos.dev_attr.attr,
&iio_dev_attr_bvrmsos.dev_attr.attr,
&iio_dev_attr_cvrmsos.dev_attr.attr,
NULL,
};
static const struct attribute_group ade7754_attribute_group = {
.attrs = ade7754_attributes,
};
static const struct iio_info ade7754_info = {
.attrs = &ade7754_attribute_group,
};
static int ade7754_probe(struct spi_device *spi)
{
int ret;
struct ade7754_state *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ade7754_info;
indio_dev->modes = INDIO_DIRECT_MODE;
/* Get the device into a sane initial state */
ret = ade7754_initial_setup(indio_dev);
if (ret)
goto powerdown_on_error;
ret = iio_device_register(indio_dev);
if (ret)
goto powerdown_on_error;
return ret;
powerdown_on_error:
ade7754_stop_device(&indio_dev->dev);
return ret;
}
static int ade7754_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
ade7754_stop_device(&indio_dev->dev);
return 0;
}
static struct spi_driver ade7754_driver = {
.driver = {
.name = "ade7754",
},
.probe = ade7754_probe,
.remove = ade7754_remove,
};
module_spi_driver(ade7754_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:ad7754");

View File

@@ -1,183 +0,0 @@
/*
* ADE7758 Poly Phase Multifunction Energy Metering IC driver
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#ifndef _ADE7758_H
#define _ADE7758_H
#define ADE7758_AWATTHR 0x01
#define ADE7758_BWATTHR 0x02
#define ADE7758_CWATTHR 0x03
#define ADE7758_AVARHR 0x04
#define ADE7758_BVARHR 0x05
#define ADE7758_CVARHR 0x06
#define ADE7758_AVAHR 0x07
#define ADE7758_BVAHR 0x08
#define ADE7758_CVAHR 0x09
#define ADE7758_AIRMS 0x0A
#define ADE7758_BIRMS 0x0B
#define ADE7758_CIRMS 0x0C
#define ADE7758_AVRMS 0x0D
#define ADE7758_BVRMS 0x0E
#define ADE7758_CVRMS 0x0F
#define ADE7758_FREQ 0x10
#define ADE7758_TEMP 0x11
#define ADE7758_WFORM 0x12
#define ADE7758_OPMODE 0x13
#define ADE7758_MMODE 0x14
#define ADE7758_WAVMODE 0x15
#define ADE7758_COMPMODE 0x16
#define ADE7758_LCYCMODE 0x17
#define ADE7758_MASK 0x18
#define ADE7758_STATUS 0x19
#define ADE7758_RSTATUS 0x1A
#define ADE7758_ZXTOUT 0x1B
#define ADE7758_LINECYC 0x1C
#define ADE7758_SAGCYC 0x1D
#define ADE7758_SAGLVL 0x1E
#define ADE7758_VPINTLVL 0x1F
#define ADE7758_IPINTLVL 0x20
#define ADE7758_VPEAK 0x21
#define ADE7758_IPEAK 0x22
#define ADE7758_GAIN 0x23
#define ADE7758_AVRMSGAIN 0x24
#define ADE7758_BVRMSGAIN 0x25
#define ADE7758_CVRMSGAIN 0x26
#define ADE7758_AIGAIN 0x27
#define ADE7758_BIGAIN 0x28
#define ADE7758_CIGAIN 0x29
#define ADE7758_AWG 0x2A
#define ADE7758_BWG 0x2B
#define ADE7758_CWG 0x2C
#define ADE7758_AVARG 0x2D
#define ADE7758_BVARG 0x2E
#define ADE7758_CVARG 0x2F
#define ADE7758_AVAG 0x30
#define ADE7758_BVAG 0x31
#define ADE7758_CVAG 0x32
#define ADE7758_AVRMSOS 0x33
#define ADE7758_BVRMSOS 0x34
#define ADE7758_CVRMSOS 0x35
#define ADE7758_AIRMSOS 0x36
#define ADE7758_BIRMSOS 0x37
#define ADE7758_CIRMSOS 0x38
#define ADE7758_AWAITOS 0x39
#define ADE7758_BWAITOS 0x3A
#define ADE7758_CWAITOS 0x3B
#define ADE7758_AVAROS 0x3C
#define ADE7758_BVAROS 0x3D
#define ADE7758_CVAROS 0x3E
#define ADE7758_APHCAL 0x3F
#define ADE7758_BPHCAL 0x40
#define ADE7758_CPHCAL 0x41
#define ADE7758_WDIV 0x42
#define ADE7758_VADIV 0x44
#define ADE7758_VARDIV 0x43
#define ADE7758_APCFNUM 0x45
#define ADE7758_APCFDEN 0x46
#define ADE7758_VARCFNUM 0x47
#define ADE7758_VARCFDEN 0x48
#define ADE7758_CHKSUM 0x7E
#define ADE7758_VERSION 0x7F
#define ADE7758_READ_REG(a) a
#define ADE7758_WRITE_REG(a) ((a) | 0x80)
#define ADE7758_MAX_TX 8
#define ADE7758_MAX_RX 4
#define ADE7758_STARTUP_DELAY 1000
#define AD7758_NUM_WAVSEL 5
#define AD7758_NUM_PHSEL 3
#define AD7758_NUM_WAVESRC (AD7758_NUM_WAVSEL * AD7758_NUM_PHSEL)
#define AD7758_PHASE_A 0
#define AD7758_PHASE_B 1
#define AD7758_PHASE_C 2
#define AD7758_CURRENT 0
#define AD7758_VOLTAGE 1
#define AD7758_ACT_PWR 2
#define AD7758_REACT_PWR 3
#define AD7758_APP_PWR 4
#define AD7758_WT(p, w) (((w) << 2) | (p))
/**
* struct ade7758_state - device instance specific data
* @us: actual spi_device
* @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx, rx, read and write frequency
**/
struct ade7758_state {
struct spi_device *us;
struct iio_trigger *trig;
u8 *tx;
u8 *rx;
struct mutex buf_lock;
struct spi_transfer ring_xfer[4];
struct spi_message ring_msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
unsigned char rx_buf[8] ____cacheline_aligned;
unsigned char tx_buf[8];
};
#ifdef CONFIG_IIO_BUFFER
/* At the moment triggers are only used for ring buffer
* filling. This may change!
*/
void ade7758_remove_trigger(struct iio_dev *indio_dev);
int ade7758_probe_trigger(struct iio_dev *indio_dev);
ssize_t ade7758_read_data_from_ring(struct device *dev,
struct device_attribute *attr, char *buf);
int ade7758_configure_ring(struct iio_dev *indio_dev);
void ade7758_unconfigure_ring(struct iio_dev *indio_dev);
int ade7758_set_irq(struct device *dev, bool enable);
int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val);
int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val);
#else /* CONFIG_IIO_BUFFER */
static inline void ade7758_remove_trigger(struct iio_dev *indio_dev)
{
}
static inline int ade7758_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
}
static int ade7758_configure_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void ade7758_unconfigure_ring(struct iio_dev *indio_dev)
{
}
static inline int ade7758_initialize_ring(struct iio_ring_buffer *ring)
{
return 0;
}
static inline void ade7758_uninitialize_ring(struct iio_dev *indio_dev)
{
}
#endif /* CONFIG_IIO_BUFFER */
#endif

View File

@@ -1,955 +0,0 @@
/*
* ADE7758 Poly Phase Multifunction Energy Metering IC driver
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include "meter.h"
#include "ade7758.h"
static int __ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
st->tx[0] = ADE7758_WRITE_REG(reg_address);
st->tx[1] = val;
return spi_write(st->us, st->tx, 2);
}
int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
ret = __ade7758_spi_write_reg_8(dev, reg_address, val);
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7758_spi_write_reg_16(struct device *dev, u8 reg_address,
u16 value)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 3,
}
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7758_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7758_spi_write_reg_24(struct device *dev, u8 reg_address,
u32 value)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 4,
}
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7758_WRITE_REG(reg_address);
st->tx[1] = (value >> 16) & 0xFF;
st->tx[2] = (value >> 8) & 0xFF;
st->tx[3] = value & 0xFF;
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
mutex_unlock(&st->buf_lock);
return ret;
}
static int __ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 1,
.delay_usecs = 4,
},
{
.tx_buf = &st->tx[1],
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 1,
},
};
st->tx[0] = ADE7758_READ_REG(reg_address);
st->tx[1] = 0;
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
reg_address);
goto error_ret;
}
*val = st->rx[0];
error_ret:
return ret;
}
int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&st->buf_lock);
ret = __ade7758_spi_read_reg_8(dev, reg_address, val);
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7758_spi_read_reg_16(struct device *dev, u8 reg_address,
u16 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 1,
.delay_usecs = 4,
},
{
.tx_buf = &st->tx[1],
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7758_READ_REG(reg_address);
st->tx[1] = 0;
st->tx[2] = 0;
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
reg_address);
goto error_ret;
}
*val = (st->rx[0] << 8) | st->rx[1];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7758_spi_read_reg_24(struct device *dev, u8 reg_address,
u32 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 1,
.delay_usecs = 4,
},
{
.tx_buf = &st->tx[1],
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 3,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7758_READ_REG(reg_address);
st->tx[1] = 0;
st->tx[2] = 0;
st->tx[3] = 0;
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
reg_address);
goto error_ret;
}
*val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static ssize_t ade7758_read_8bit(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
u8 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7758_spi_read_reg_8(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7758_read_16bit(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
u16 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7758_spi_read_reg_16(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7758_read_24bit(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
u32 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7758_spi_read_reg_24(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val & 0xFFFFFF);
}
static ssize_t ade7758_write_8bit(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u8 val;
ret = kstrtou8(buf, 10, &val);
if (ret)
goto error_ret;
ret = ade7758_spi_write_reg_8(dev, this_attr->address, val);
error_ret:
return ret ? ret : len;
}
static ssize_t ade7758_write_16bit(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u16 val;
ret = kstrtou16(buf, 10, &val);
if (ret)
goto error_ret;
ret = ade7758_spi_write_reg_16(dev, this_attr->address, val);
error_ret:
return ret ? ret : len;
}
static int ade7758_reset(struct device *dev)
{
int ret;
u8 val;
ret = ade7758_spi_read_reg_8(dev, ADE7758_OPMODE, &val);
if (ret < 0) {
dev_err(dev, "Failed to read opmode reg\n");
return ret;
}
val |= BIT(6); /* Software Chip Reset */
ret = ade7758_spi_write_reg_8(dev, ADE7758_OPMODE, val);
if (ret < 0)
dev_err(dev, "Failed to write opmode reg\n");
return ret;
}
static IIO_DEV_ATTR_VPEAK(0644,
ade7758_read_8bit,
ade7758_write_8bit,
ADE7758_VPEAK);
static IIO_DEV_ATTR_IPEAK(0644,
ade7758_read_8bit,
ade7758_write_8bit,
ADE7758_VPEAK);
static IIO_DEV_ATTR_APHCAL(0644,
ade7758_read_8bit,
ade7758_write_8bit,
ADE7758_APHCAL);
static IIO_DEV_ATTR_BPHCAL(0644,
ade7758_read_8bit,
ade7758_write_8bit,
ADE7758_BPHCAL);
static IIO_DEV_ATTR_CPHCAL(0644,
ade7758_read_8bit,
ade7758_write_8bit,
ADE7758_CPHCAL);
static IIO_DEV_ATTR_WDIV(0644,
ade7758_read_8bit,
ade7758_write_8bit,
ADE7758_WDIV);
static IIO_DEV_ATTR_VADIV(0644,
ade7758_read_8bit,
ade7758_write_8bit,
ADE7758_VADIV);
static IIO_DEV_ATTR_AIRMS(0444,
ade7758_read_24bit,
NULL,
ADE7758_AIRMS);
static IIO_DEV_ATTR_BIRMS(0444,
ade7758_read_24bit,
NULL,
ADE7758_BIRMS);
static IIO_DEV_ATTR_CIRMS(0444,
ade7758_read_24bit,
NULL,
ADE7758_CIRMS);
static IIO_DEV_ATTR_AVRMS(0444,
ade7758_read_24bit,
NULL,
ADE7758_AVRMS);
static IIO_DEV_ATTR_BVRMS(0444,
ade7758_read_24bit,
NULL,
ADE7758_BVRMS);
static IIO_DEV_ATTR_CVRMS(0444,
ade7758_read_24bit,
NULL,
ADE7758_CVRMS);
static IIO_DEV_ATTR_AIRMSOS(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_AIRMSOS);
static IIO_DEV_ATTR_BIRMSOS(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_BIRMSOS);
static IIO_DEV_ATTR_CIRMSOS(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_CIRMSOS);
static IIO_DEV_ATTR_AVRMSOS(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_AVRMSOS);
static IIO_DEV_ATTR_BVRMSOS(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_BVRMSOS);
static IIO_DEV_ATTR_CVRMSOS(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_CVRMSOS);
static IIO_DEV_ATTR_AIGAIN(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_AIGAIN);
static IIO_DEV_ATTR_BIGAIN(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_BIGAIN);
static IIO_DEV_ATTR_CIGAIN(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_CIGAIN);
static IIO_DEV_ATTR_AVRMSGAIN(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_AVRMSGAIN);
static IIO_DEV_ATTR_BVRMSGAIN(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_BVRMSGAIN);
static IIO_DEV_ATTR_CVRMSGAIN(0644,
ade7758_read_16bit,
ade7758_write_16bit,
ADE7758_CVRMSGAIN);
int ade7758_set_irq(struct device *dev, bool enable)
{
int ret;
u32 irqen;
ret = ade7758_spi_read_reg_24(dev, ADE7758_MASK, &irqen);
if (ret)
return ret;
if (enable)
irqen |= BIT(16); /* Enables an interrupt when a data is
* present in the waveform register
*/
else
irqen &= ~BIT(16);
ret = ade7758_spi_write_reg_24(dev, ADE7758_MASK, irqen);
return ret;
}
/* Power down the device */
static int ade7758_stop_device(struct device *dev)
{
int ret;
u8 val;
ret = ade7758_spi_read_reg_8(dev, ADE7758_OPMODE, &val);
if (ret < 0) {
dev_err(dev, "Failed to read opmode reg\n");
return ret;
}
val |= 7 << 3; /* ADE7758 powered down */
ret = ade7758_spi_write_reg_8(dev, ADE7758_OPMODE, val);
if (ret < 0)
dev_err(dev, "Failed to write opmode reg\n");
return ret;
}
static int ade7758_initial_setup(struct iio_dev *indio_dev)
{
struct ade7758_state *st = iio_priv(indio_dev);
struct device *dev = &indio_dev->dev;
int ret;
/* use low spi speed for init */
st->us->mode = SPI_MODE_1;
spi_setup(st->us);
/* Disable IRQ */
ret = ade7758_set_irq(dev, false);
if (ret) {
dev_err(dev, "disable irq failed");
goto err_ret;
}
ade7758_reset(dev);
usleep_range(ADE7758_STARTUP_DELAY, ADE7758_STARTUP_DELAY + 100);
err_ret:
return ret;
}
static int ade7758_read_samp_freq(struct device *dev, int *val)
{
int ret;
u8 t;
ret = ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &t);
if (ret)
return ret;
t = (t >> 5) & 0x3;
*val = 26040 / (1 << t);
return 0;
}
static int ade7758_write_samp_freq(struct device *dev, int val)
{
int ret;
u8 reg, t;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
switch (val) {
case 26040:
t = 0;
break;
case 13020:
t = 1;
break;
case 6510:
t = 2;
break;
case 3255:
t = 3;
break;
default:
return -EINVAL;
}
mutex_lock(&st->buf_lock);
ret = __ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &reg);
if (ret)
goto out;
reg &= ~(5 << 3);
reg |= t << 5;
ret = __ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg);
out:
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7758_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
int ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
ret = ade7758_read_samp_freq(&indio_dev->dev, val);
return ret;
default:
return -EINVAL;
}
return ret;
}
static int ade7758_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
if (val2)
return -EINVAL;
ret = ade7758_write_samp_freq(&indio_dev->dev, val);
return ret;
default:
return -EINVAL;
}
return ret;
}
static IIO_DEV_ATTR_TEMP_RAW(ade7758_read_8bit);
static IIO_CONST_ATTR(in_temp_offset, "129 C");
static IIO_CONST_ATTR(in_temp_scale, "4 C");
static IIO_DEV_ATTR_AWATTHR(ade7758_read_16bit,
ADE7758_AWATTHR);
static IIO_DEV_ATTR_BWATTHR(ade7758_read_16bit,
ADE7758_BWATTHR);
static IIO_DEV_ATTR_CWATTHR(ade7758_read_16bit,
ADE7758_CWATTHR);
static IIO_DEV_ATTR_AVARHR(ade7758_read_16bit,
ADE7758_AVARHR);
static IIO_DEV_ATTR_BVARHR(ade7758_read_16bit,
ADE7758_BVARHR);
static IIO_DEV_ATTR_CVARHR(ade7758_read_16bit,
ADE7758_CVARHR);
static IIO_DEV_ATTR_AVAHR(ade7758_read_16bit,
ADE7758_AVAHR);
static IIO_DEV_ATTR_BVAHR(ade7758_read_16bit,
ADE7758_BVAHR);
static IIO_DEV_ATTR_CVAHR(ade7758_read_16bit,
ADE7758_CVAHR);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26040 13020 6510 3255");
static struct attribute *ade7758_attributes[] = {
&iio_dev_attr_in_temp_raw.dev_attr.attr,
&iio_const_attr_in_temp_offset.dev_attr.attr,
&iio_const_attr_in_temp_scale.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_awatthr.dev_attr.attr,
&iio_dev_attr_bwatthr.dev_attr.attr,
&iio_dev_attr_cwatthr.dev_attr.attr,
&iio_dev_attr_avarhr.dev_attr.attr,
&iio_dev_attr_bvarhr.dev_attr.attr,
&iio_dev_attr_cvarhr.dev_attr.attr,
&iio_dev_attr_avahr.dev_attr.attr,
&iio_dev_attr_bvahr.dev_attr.attr,
&iio_dev_attr_cvahr.dev_attr.attr,
&iio_dev_attr_vpeak.dev_attr.attr,
&iio_dev_attr_ipeak.dev_attr.attr,
&iio_dev_attr_aphcal.dev_attr.attr,
&iio_dev_attr_bphcal.dev_attr.attr,
&iio_dev_attr_cphcal.dev_attr.attr,
&iio_dev_attr_wdiv.dev_attr.attr,
&iio_dev_attr_vadiv.dev_attr.attr,
&iio_dev_attr_airms.dev_attr.attr,
&iio_dev_attr_birms.dev_attr.attr,
&iio_dev_attr_cirms.dev_attr.attr,
&iio_dev_attr_avrms.dev_attr.attr,
&iio_dev_attr_bvrms.dev_attr.attr,
&iio_dev_attr_cvrms.dev_attr.attr,
&iio_dev_attr_aigain.dev_attr.attr,
&iio_dev_attr_bigain.dev_attr.attr,
&iio_dev_attr_cigain.dev_attr.attr,
&iio_dev_attr_avrmsgain.dev_attr.attr,
&iio_dev_attr_bvrmsgain.dev_attr.attr,
&iio_dev_attr_cvrmsgain.dev_attr.attr,
&iio_dev_attr_airmsos.dev_attr.attr,
&iio_dev_attr_birmsos.dev_attr.attr,
&iio_dev_attr_cirmsos.dev_attr.attr,
&iio_dev_attr_avrmsos.dev_attr.attr,
&iio_dev_attr_bvrmsos.dev_attr.attr,
&iio_dev_attr_cvrmsos.dev_attr.attr,
NULL,
};
static const struct attribute_group ade7758_attribute_group = {
.attrs = ade7758_attributes,
};
static const struct iio_chan_spec ade7758_channels[] = {
{
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_CURRENT,
.indexed = 1,
.channel = 0,
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT),
.scan_index = 1,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_POWER,
.indexed = 1,
.channel = 0,
.extend_name = "apparent",
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR),
.scan_index = 2,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_POWER,
.indexed = 1,
.channel = 0,
.extend_name = "active",
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR),
.scan_index = 3,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_POWER,
.indexed = 1,
.channel = 0,
.extend_name = "reactive",
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR),
.scan_index = 4,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE),
.scan_index = 5,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_CURRENT,
.indexed = 1,
.channel = 1,
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT),
.scan_index = 6,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_POWER,
.indexed = 1,
.channel = 1,
.extend_name = "apparent",
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR),
.scan_index = 7,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_POWER,
.indexed = 1,
.channel = 1,
.extend_name = "active",
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR),
.scan_index = 8,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_POWER,
.indexed = 1,
.channel = 1,
.extend_name = "reactive",
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR),
.scan_index = 9,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE),
.scan_index = 10,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_CURRENT,
.indexed = 1,
.channel = 2,
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT),
.scan_index = 11,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_POWER,
.indexed = 1,
.channel = 2,
.extend_name = "apparent",
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR),
.scan_index = 12,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_POWER,
.indexed = 1,
.channel = 2,
.extend_name = "active",
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR),
.scan_index = 13,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
}, {
.type = IIO_POWER,
.indexed = 1,
.channel = 2,
.extend_name = "reactive",
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR),
.scan_index = 14,
.scan_type = {
.sign = 's',
.realbits = 24,
.storagebits = 32,
},
},
IIO_CHAN_SOFT_TIMESTAMP(15),
};
static const struct iio_info ade7758_info = {
.attrs = &ade7758_attribute_group,
.read_raw = &ade7758_read_raw,
.write_raw = &ade7758_write_raw,
};
static int ade7758_probe(struct spi_device *spi)
{
int ret;
struct ade7758_state *st;
struct iio_dev *indio_dev;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
/* Allocate the comms buffers */
st->rx = kcalloc(ADE7758_MAX_RX, sizeof(*st->rx), GFP_KERNEL);
if (!st->rx)
return -ENOMEM;
st->tx = kcalloc(ADE7758_MAX_TX, sizeof(*st->tx), GFP_KERNEL);
if (!st->tx) {
ret = -ENOMEM;
goto error_free_rx;
}
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ade7758_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ade7758_channels;
indio_dev->num_channels = ARRAY_SIZE(ade7758_channels);
ret = ade7758_configure_ring(indio_dev);
if (ret)
goto error_free_tx;
/* Get the device into a sane initial state */
ret = ade7758_initial_setup(indio_dev);
if (ret)
goto error_unreg_ring_funcs;
if (spi->irq) {
ret = ade7758_probe_trigger(indio_dev);
if (ret)
goto error_unreg_ring_funcs;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
return 0;
error_remove_trigger:
if (spi->irq)
ade7758_remove_trigger(indio_dev);
error_unreg_ring_funcs:
ade7758_unconfigure_ring(indio_dev);
error_free_tx:
kfree(st->tx);
error_free_rx:
kfree(st->rx);
return ret;
}
static int ade7758_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ade7758_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
ade7758_stop_device(&indio_dev->dev);
ade7758_remove_trigger(indio_dev);
ade7758_unconfigure_ring(indio_dev);
kfree(st->tx);
kfree(st->rx);
return 0;
}
static const struct spi_device_id ade7758_id[] = {
{"ade7758", 0},
{}
};
MODULE_DEVICE_TABLE(spi, ade7758_id);
static struct spi_driver ade7758_driver = {
.driver = {
.name = "ade7758",
},
.probe = ade7758_probe,
.remove = ade7758_remove,
.id_table = ade7758_id,
};
module_spi_driver(ade7758_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADE7758 Polyphase Multifunction Energy Metering IC Driver");
MODULE_LICENSE("GPL v2");

View File

@@ -1,177 +0,0 @@
/*
* ADE7758 Poly Phase Multifunction Energy Metering IC driver
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger_consumer.h>
#include "ade7758.h"
/**
* ade7758_spi_read_burst() - read data registers
* @indio_dev: the IIO device
**/
static int ade7758_spi_read_burst(struct iio_dev *indio_dev)
{
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
ret = spi_sync(st->us, &st->ring_msg);
if (ret)
dev_err(&st->us->dev, "problem when reading WFORM value\n");
return ret;
}
static int ade7758_write_waveform_type(struct device *dev, unsigned int type)
{
int ret;
u8 reg;
ret = ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &reg);
if (ret)
goto out;
reg &= ~0x1F;
reg |= type & 0x1F;
ret = ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg);
out:
return ret;
}
/* Whilst this makes a lot of calls to iio_sw_ring functions - it is too device
* specific to be rolled into the core.
*/
static irqreturn_t ade7758_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ade7758_state *st = iio_priv(indio_dev);
s64 dat64[2];
u32 *dat32 = (u32 *)dat64;
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
if (ade7758_spi_read_burst(indio_dev) >= 0)
*dat32 = get_unaligned_be32(&st->rx_buf[5]) & 0xFFFFFF;
iio_push_to_buffers_with_timestamp(indio_dev, dat64, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
/**
* ade7758_ring_preenable() setup the parameters of the ring before enabling
*
* The complex nature of the setting of the number of bytes per datum is due
* to this driver currently ensuring that the timestamp is stored at an 8
* byte boundary.
**/
static int ade7758_ring_preenable(struct iio_dev *indio_dev)
{
unsigned int channel;
if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
return -EINVAL;
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
ade7758_write_waveform_type(&indio_dev->dev,
indio_dev->channels[channel].address);
return 0;
}
static const struct iio_buffer_setup_ops ade7758_ring_setup_ops = {
.preenable = &ade7758_ring_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
.validate_scan_mask = &iio_validate_scan_mask_onehot,
};
void ade7758_unconfigure_ring(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_kfifo_free(indio_dev->buffer);
}
int ade7758_configure_ring(struct iio_dev *indio_dev)
{
struct ade7758_state *st = iio_priv(indio_dev);
struct iio_buffer *buffer;
int ret = 0;
buffer = iio_kfifo_allocate();
if (!buffer)
return -ENOMEM;
iio_device_attach_buffer(indio_dev, buffer);
indio_dev->setup_ops = &ade7758_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&ade7758_trigger_handler,
0,
indio_dev,
"ade7759_consumer%d",
indio_dev->id);
if (!indio_dev->pollfunc) {
ret = -ENOMEM;
goto error_iio_kfifo_free;
}
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
st->tx_buf[0] = ADE7758_READ_REG(ADE7758_RSTATUS);
st->tx_buf[1] = 0;
st->tx_buf[2] = 0;
st->tx_buf[3] = 0;
st->tx_buf[4] = ADE7758_READ_REG(ADE7758_WFORM);
st->tx_buf[5] = 0;
st->tx_buf[6] = 0;
st->tx_buf[7] = 0;
/* build spi ring message */
st->ring_xfer[0].tx_buf = &st->tx_buf[0];
st->ring_xfer[0].len = 1;
st->ring_xfer[0].bits_per_word = 8;
st->ring_xfer[0].delay_usecs = 4;
st->ring_xfer[1].rx_buf = &st->rx_buf[1];
st->ring_xfer[1].len = 3;
st->ring_xfer[1].bits_per_word = 8;
st->ring_xfer[1].cs_change = 1;
st->ring_xfer[2].tx_buf = &st->tx_buf[4];
st->ring_xfer[2].len = 1;
st->ring_xfer[2].bits_per_word = 8;
st->ring_xfer[2].delay_usecs = 1;
st->ring_xfer[3].rx_buf = &st->rx_buf[5];
st->ring_xfer[3].len = 3;
st->ring_xfer[3].bits_per_word = 8;
spi_message_init(&st->ring_msg);
spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg);
spi_message_add_tail(&st->ring_xfer[2], &st->ring_msg);
spi_message_add_tail(&st->ring_xfer[3], &st->ring_msg);
return 0;
error_iio_kfifo_free:
iio_kfifo_free(indio_dev->buffer);
return ret;
}

View File

@@ -1,108 +0,0 @@
/*
* ADE7758 Poly Phase Multifunction Energy Metering IC driver
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include "ade7758.h"
/**
* ade7758_data_rdy_trig_poll() the event handler for the data rdy trig
**/
static irqreturn_t ade7758_data_rdy_trig_poll(int irq, void *private)
{
disable_irq_nosync(irq);
iio_trigger_poll(private);
return IRQ_HANDLED;
}
/**
* ade7758_data_rdy_trigger_set_state() set datardy interrupt state
**/
static int ade7758_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
dev_dbg(&indio_dev->dev, "(%d)\n", state);
return ade7758_set_irq(&indio_dev->dev, state);
}
/**
* ade7758_trig_try_reen() try renabling irq for data rdy trigger
* @trig: the datardy trigger
**/
static int ade7758_trig_try_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct ade7758_state *st = iio_priv(indio_dev);
enable_irq(st->us->irq);
/* irq reenabled so success! */
return 0;
}
static const struct iio_trigger_ops ade7758_trigger_ops = {
.set_trigger_state = &ade7758_data_rdy_trigger_set_state,
.try_reenable = &ade7758_trig_try_reen,
};
int ade7758_probe_trigger(struct iio_dev *indio_dev)
{
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->us)->name,
indio_dev->id);
if (!st->trig) {
ret = -ENOMEM;
goto error_ret;
}
ret = request_irq(st->us->irq,
ade7758_data_rdy_trig_poll,
IRQF_TRIGGER_LOW,
spi_get_device_id(st->us)->name,
st->trig);
if (ret)
goto error_free_trig;
st->trig->dev.parent = &st->us->dev;
st->trig->ops = &ade7758_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev);
ret = iio_trigger_register(st->trig);
/* select default trigger */
indio_dev->trig = iio_trigger_get(st->trig);
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
iio_trigger_free(st->trig);
error_ret:
return ret;
}
void ade7758_remove_trigger(struct iio_dev *indio_dev)
{
struct ade7758_state *st = iio_priv(indio_dev);
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
iio_trigger_free(st->trig);
}

View File

@@ -1,558 +0,0 @@
/*
* ADE7759 Active Energy Metering IC with di/dt Sensor Interface Driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "meter.h"
#define ADE7759_WAVEFORM 0x01
#define ADE7759_AENERGY 0x02
#define ADE7759_RSTENERGY 0x03
#define ADE7759_STATUS 0x04
#define ADE7759_RSTSTATUS 0x05
#define ADE7759_MODE 0x06
#define ADE7759_CFDEN 0x07
#define ADE7759_CH1OS 0x08
#define ADE7759_CH2OS 0x09
#define ADE7759_GAIN 0x0A
#define ADE7759_APGAIN 0x0B
#define ADE7759_PHCAL 0x0C
#define ADE7759_APOS 0x0D
#define ADE7759_ZXTOUT 0x0E
#define ADE7759_SAGCYC 0x0F
#define ADE7759_IRQEN 0x10
#define ADE7759_SAGLVL 0x11
#define ADE7759_TEMP 0x12
#define ADE7759_LINECYC 0x13
#define ADE7759_LENERGY 0x14
#define ADE7759_CFNUM 0x15
#define ADE7759_CHKSUM 0x1E
#define ADE7759_DIEREV 0x1F
#define ADE7759_READ_REG(a) a
#define ADE7759_WRITE_REG(a) ((a) | 0x80)
#define ADE7759_MAX_TX 6
#define ADE7759_MAX_RX 6
#define ADE7759_STARTUP_DELAY 1000
#define ADE7759_SPI_SLOW (u32)(300 * 1000)
#define ADE7759_SPI_BURST (u32)(1000 * 1000)
#define ADE7759_SPI_FAST (u32)(2000 * 1000)
/**
* struct ade7759_state - device instance specific data
* @us: actual spi_device
* @buf_lock: mutex to protect tx and rx and write frequency
* @tx: transmit buffer
* @rx: receive buffer
**/
struct ade7759_state {
struct spi_device *us;
struct mutex buf_lock;
u8 tx[ADE7759_MAX_TX] ____cacheline_aligned;
u8 rx[ADE7759_MAX_RX];
};
static int ade7759_spi_write_reg_8(struct device *dev,
u8 reg_address,
u8 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7759_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
/*Unlocked version of ade7759_spi_write_reg_16 function */
static int __ade7759_spi_write_reg_16(struct device *dev,
u8 reg_address,
u16 value)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
st->tx[0] = ADE7759_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
return spi_write(st->us, st->tx, 3);
}
static int ade7759_spi_write_reg_16(struct device *dev,
u8 reg_address,
u16 value)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
ret = __ade7759_spi_write_reg_16(dev, reg_address, value);
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7759_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
int ret;
ret = spi_w8r8(st->us, ADE7759_READ_REG(reg_address));
if (ret < 0) {
dev_err(&st->us->dev,
"problem when reading 8 bit register 0x%02X",
reg_address);
return ret;
}
*val = ret;
return 0;
}
static int ade7759_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
int ret;
ret = spi_w8r16be(st->us, ADE7759_READ_REG(reg_address));
if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
reg_address);
return ret;
}
*val = ret;
return 0;
}
static int ade7759_spi_read_reg_40(struct device *dev,
u8 reg_address,
u64 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 6,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7759_READ_REG(reg_address);
memset(&st->tx[1], 0, 5);
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->us->dev,
"problem when reading 40 bit register 0x%02X",
reg_address);
goto error_ret;
}
*val = ((u64)st->rx[1] << 32) | ((u64)st->rx[2] << 24) |
(st->rx[3] << 16) | (st->rx[4] << 8) | st->rx[5];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static ssize_t ade7759_read_8bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u8 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7759_spi_read_reg_8(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7759_read_16bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u16 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7759_spi_read_reg_16(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7759_read_40bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u64 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7759_spi_read_reg_40(dev, this_attr->address, &val);
if (ret)
return ret;
return sprintf(buf, "%llu\n", val);
}
static ssize_t ade7759_write_8bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u8 val;
ret = kstrtou8(buf, 10, &val);
if (ret)
goto error_ret;
ret = ade7759_spi_write_reg_8(dev, this_attr->address, val);
error_ret:
return ret ? ret : len;
}
static ssize_t ade7759_write_16bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u16 val;
ret = kstrtou16(buf, 10, &val);
if (ret)
goto error_ret;
ret = ade7759_spi_write_reg_16(dev, this_attr->address, val);
error_ret:
return ret ? ret : len;
}
static int ade7759_reset(struct device *dev)
{
int ret;
u16 val;
ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val);
if (ret < 0)
return ret;
val |= BIT(6); /* Software Chip Reset */
return ade7759_spi_write_reg_16(dev,
ADE7759_MODE,
val);
}
static IIO_DEV_ATTR_AENERGY(ade7759_read_40bit, ADE7759_AENERGY);
static IIO_DEV_ATTR_CFDEN(0644,
ade7759_read_16bit,
ade7759_write_16bit,
ADE7759_CFDEN);
static IIO_DEV_ATTR_CFNUM(0644,
ade7759_read_8bit,
ade7759_write_8bit,
ADE7759_CFNUM);
static IIO_DEV_ATTR_CHKSUM(ade7759_read_8bit, ADE7759_CHKSUM);
static IIO_DEV_ATTR_PHCAL(0644,
ade7759_read_16bit,
ade7759_write_16bit,
ADE7759_PHCAL);
static IIO_DEV_ATTR_APOS(0644,
ade7759_read_16bit,
ade7759_write_16bit,
ADE7759_APOS);
static IIO_DEV_ATTR_SAGCYC(0644,
ade7759_read_8bit,
ade7759_write_8bit,
ADE7759_SAGCYC);
static IIO_DEV_ATTR_SAGLVL(0644,
ade7759_read_8bit,
ade7759_write_8bit,
ADE7759_SAGLVL);
static IIO_DEV_ATTR_LINECYC(0644,
ade7759_read_8bit,
ade7759_write_8bit,
ADE7759_LINECYC);
static IIO_DEV_ATTR_LENERGY(ade7759_read_40bit, ADE7759_LENERGY);
static IIO_DEV_ATTR_PGA_GAIN(0644,
ade7759_read_8bit,
ade7759_write_8bit,
ADE7759_GAIN);
static IIO_DEV_ATTR_ACTIVE_POWER_GAIN(0644,
ade7759_read_16bit,
ade7759_write_16bit,
ADE7759_APGAIN);
static IIO_DEVICE_ATTR(choff_1, 0644,
ade7759_read_8bit,
ade7759_write_8bit,
ADE7759_CH1OS);
static IIO_DEVICE_ATTR(choff_2, 0644,
ade7759_read_8bit,
ade7759_write_8bit,
ADE7759_CH2OS);
static int ade7759_set_irq(struct device *dev, bool enable)
{
int ret;
u8 irqen;
ret = ade7759_spi_read_reg_8(dev, ADE7759_IRQEN, &irqen);
if (ret)
goto error_ret;
if (enable)
irqen |= BIT(3); /* Enables an interrupt when a data is
* present in the waveform register
*/
else
irqen &= ~BIT(3);
ret = ade7759_spi_write_reg_8(dev, ADE7759_IRQEN, irqen);
error_ret:
return ret;
}
/* Power down the device */
static int ade7759_stop_device(struct device *dev)
{
int ret;
u16 val;
ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val);
if (ret < 0) {
dev_err(dev, "unable to power down the device, error: %d\n",
ret);
return ret;
}
val |= BIT(4); /* AD converters can be turned off */
return ade7759_spi_write_reg_16(dev, ADE7759_MODE, val);
}
static int ade7759_initial_setup(struct iio_dev *indio_dev)
{
int ret;
struct ade7759_state *st = iio_priv(indio_dev);
struct device *dev = &indio_dev->dev;
/* use low spi speed for init */
st->us->mode = SPI_MODE_3;
spi_setup(st->us);
/* Disable IRQ */
ret = ade7759_set_irq(dev, false);
if (ret) {
dev_err(dev, "disable irq failed");
goto err_ret;
}
ade7759_reset(dev);
usleep_range(ADE7759_STARTUP_DELAY, ADE7759_STARTUP_DELAY + 100);
err_ret:
return ret;
}
static ssize_t ade7759_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u16 t;
int sps;
ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &t);
if (ret)
return ret;
t = (t >> 3) & 0x3;
sps = 27900 / (1 + t);
return sprintf(buf, "%d\n", sps);
}
static ssize_t ade7759_write_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
u16 val;
int ret;
u16 reg, t;
ret = kstrtou16(buf, 10, &val);
if (ret)
return ret;
if (!val)
return -EINVAL;
mutex_lock(&st->buf_lock);
t = 27900 / val;
if (t > 0)
t--;
if (t > 1)
st->us->max_speed_hz = ADE7759_SPI_SLOW;
else
st->us->max_speed_hz = ADE7759_SPI_FAST;
ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &reg);
if (ret)
goto out;
reg &= ~(3 << 13);
reg |= t << 13;
ret = __ade7759_spi_write_reg_16(dev, ADE7759_MODE, reg);
out:
mutex_unlock(&st->buf_lock);
return ret ? ret : len;
}
static IIO_DEV_ATTR_TEMP_RAW(ade7759_read_8bit);
static IIO_CONST_ATTR(in_temp_offset, "70 C");
static IIO_CONST_ATTR(in_temp_scale, "1 C");
static IIO_DEV_ATTR_SAMP_FREQ(0644,
ade7759_read_frequency,
ade7759_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
static struct attribute *ade7759_attributes[] = {
&iio_dev_attr_in_temp_raw.dev_attr.attr,
&iio_const_attr_in_temp_offset.dev_attr.attr,
&iio_const_attr_in_temp_scale.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_phcal.dev_attr.attr,
&iio_dev_attr_cfden.dev_attr.attr,
&iio_dev_attr_aenergy.dev_attr.attr,
&iio_dev_attr_cfnum.dev_attr.attr,
&iio_dev_attr_apos.dev_attr.attr,
&iio_dev_attr_sagcyc.dev_attr.attr,
&iio_dev_attr_saglvl.dev_attr.attr,
&iio_dev_attr_linecyc.dev_attr.attr,
&iio_dev_attr_lenergy.dev_attr.attr,
&iio_dev_attr_chksum.dev_attr.attr,
&iio_dev_attr_pga_gain.dev_attr.attr,
&iio_dev_attr_active_power_gain.dev_attr.attr,
&iio_dev_attr_choff_1.dev_attr.attr,
&iio_dev_attr_choff_2.dev_attr.attr,
NULL,
};
static const struct attribute_group ade7759_attribute_group = {
.attrs = ade7759_attributes,
};
static const struct iio_info ade7759_info = {
.attrs = &ade7759_attribute_group,
};
static int ade7759_probe(struct spi_device *spi)
{
int ret;
struct ade7759_state *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ade7759_info;
indio_dev->modes = INDIO_DIRECT_MODE;
/* Get the device into a sane initial state */
ret = ade7759_initial_setup(indio_dev);
if (ret)
return ret;
return iio_device_register(indio_dev);
}
static int ade7759_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
ade7759_stop_device(&indio_dev->dev);
return 0;
}
static struct spi_driver ade7759_driver = {
.driver = {
.name = "ade7759",
},
.probe = ade7759_probe,
.remove = ade7759_remove,
};
module_spi_driver(ade7759_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADE7759 Active Energy Metering IC Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:ad7759");

View File

@@ -13,18 +13,6 @@ config AD2S90
To compile this driver as a module, choose M here: the
module will be called ad2s90.
config AD2S1200
tristate "Analog Devices ad2s1200/ad2s1205 driver"
depends on SPI
depends on GPIOLIB || COMPILE_TEST
help
Say yes here to build support for Analog Devices spi resolver
to digital converters, ad2s1200 and ad2s1205, provides direct access
via sysfs.
To compile this driver as a module, choose M here: the
module will be called ad2s1200.
config AD2S1210
tristate "Analog Devices ad2s1210 driver"
depends on SPI

View File

@@ -3,5 +3,4 @@
#
obj-$(CONFIG_AD2S90) += ad2s90.o
obj-$(CONFIG_AD2S1200) += ad2s1200.o
obj-$(CONFIG_AD2S1210) += ad2s1210.o

View File

@@ -9,6 +9,8 @@
#ifndef STM32_DFSDM_ADC_H
#define STM32_DFSDM_ADC_H
#include <linux/iio/iio.h>
int stm32_dfsdm_get_buff_cb(struct iio_dev *iio_dev,
int (*cb)(const void *data, size_t size,
void *private),

View File

@@ -1,51 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Device driver for monitoring ambient light intensity (lux)
* and proximity (prox) within the TAOS TSL2X7X family of devices.
* and proximity (prox) within the TAOS TSL2772 family of devices.
*
* Copyright (c) 2012, TAOS Corporation.
* Copyright (c) 2017-2018 Brian Masney <masneyb@onstation.org>
*/
#ifndef __TSL2X7X_H
#define __TSL2X7X_H
#ifndef __TSL2772_H
#define __TSL2772_H
struct tsl2x7x_lux {
struct tsl2772_lux {
unsigned int ch0;
unsigned int ch1;
};
/* Max number of segments allowable in LUX table */
#define TSL2X7X_MAX_LUX_TABLE_SIZE 6
#define TSL2772_MAX_LUX_TABLE_SIZE 6
/* The default LUX tables all have 3 elements. */
#define TSL2X7X_DEF_LUX_TABLE_SZ 3
#define TSL2X7X_DEFAULT_TABLE_BYTES (sizeof(struct tsl2x7x_lux) * \
TSL2X7X_DEF_LUX_TABLE_SZ)
#define TSL2772_DEF_LUX_TABLE_SZ 3
#define TSL2772_DEFAULT_TABLE_BYTES (sizeof(struct tsl2772_lux) * \
TSL2772_DEF_LUX_TABLE_SZ)
/* Proximity diode to use */
#define TSL2X7X_DIODE0 0x01
#define TSL2X7X_DIODE1 0x02
#define TSL2X7X_DIODE_BOTH 0x03
#define TSL2772_DIODE0 0x01
#define TSL2772_DIODE1 0x02
#define TSL2772_DIODE_BOTH 0x03
/* LED Power */
#define TSL2X7X_100_mA 0x00
#define TSL2X7X_50_mA 0x01
#define TSL2X7X_25_mA 0x02
#define TSL2X7X_13_mA 0x03
#define TSL2X7X_MAX_TIMER_CNT 0xFF
#define TSL2772_100_mA 0x00
#define TSL2772_50_mA 0x01
#define TSL2772_25_mA 0x02
#define TSL2772_13_mA 0x03
/**
* struct tsl2x7x_settings - Settings for the tsl2x7x driver
* struct tsl2772_settings - Settings for the tsl2772 driver
* @als_time: Integration time of the ALS channel ADCs in 2.73 ms
* increments. Total integration time is
* (256 - als_time) * 2.73.
* @als_gain: Index into the tsl2x7x_als_gain array.
* @als_gain: Index into the tsl2772_als_gain array.
* @als_gain_trim: Default gain trim to account for aperture effects.
* @wait_time: Time between proximity and ALS cycles in 2.73
* periods.
* @prox_time: Integration time of the proximity ADC in 2.73 ms
* increments. Total integration time is
* (256 - prx_time) * 2.73.
* @prox_gain: Index into the tsl2x7x_prx_gain array.
* @prox_gain: Index into the tsl2772_prx_gain array.
* @als_prox_config: The value of the ALS / Proximity configuration
* register.
* @als_cal_target: Known external ALS reading for calibration.
@@ -65,7 +65,7 @@ struct tsl2x7x_lux {
* LED(s) for proximity sensing.
* @prox_power The amount of power to use for the external LED(s).
*/
struct tsl2x7x_settings {
struct tsl2772_settings {
int als_time;
int als_gain;
int als_gain_trim;
@@ -89,14 +89,13 @@ struct tsl2x7x_settings {
};
/**
* struct tsl2X7X_platform_data - Platform callback, glass and defaults
* struct tsl2772_platform_data - Platform callback, glass and defaults
* @platform_lux_table: Device specific glass coefficents
* @platform_default_settings: Device specific power on defaults
*
*/
struct tsl2X7X_platform_data {
struct tsl2x7x_lux platform_lux_table[TSL2X7X_MAX_LUX_TABLE_SIZE];
struct tsl2x7x_settings *platform_default_settings;
struct tsl2772_platform_data {
struct tsl2772_lux platform_lux_table[TSL2772_MAX_LUX_TABLE_SIZE];
struct tsl2772_settings *platform_default_settings;
};
#endif /* __TSL2X7X_H */
#endif /* __TSL2772_H */

View File

@@ -248,7 +248,7 @@ void print_usage(void)
"Capture, convert and output data from IIO device buffer\n"
" -a Auto-activate all available channels\n"
" -A Force-activate ALL channels\n"
" -c <n> Do n conversions\n"
" -c <n> Do n conversions, or loop forever if n < 0\n"
" -e Disable wait for event (new data)\n"
" -g Use trigger-less mode\n"
" -l <n> Set buffer length to n samples\n"
@@ -330,11 +330,14 @@ static const struct option longopts[] = {
int main(int argc, char **argv)
{
unsigned long num_loops = 2;
unsigned long long num_loops = 2;
unsigned long timedelay = 1000000;
unsigned long buf_len = 128;
int ret, c, i, j, toread;
ssize_t i;
unsigned long long j;
unsigned long toread;
int ret, c;
int fp = -1;
int num_channels = 0;
@@ -366,7 +369,7 @@ int main(int argc, char **argv)
break;
case 'c':
errno = 0;
num_loops = strtoul(optarg, &dummy, 10);
num_loops = strtoll(optarg, &dummy, 10);
if (errno) {
ret = -errno;
goto error;
@@ -634,7 +637,7 @@ int main(int argc, char **argv)
goto error;
}
for (j = 0; j < num_loops; j++) {
for (j = 0; j < num_loops || num_loops < 0; j++) {
if (!noevents) {
struct pollfd pfd = {
.fd = fp,