mirror of
https://github.com/hardkernel/linux.git
synced 2026-05-31 00:06:41 +09:00
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:
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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 */
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
17
drivers/iio/resolver/Kconfig
Normal file
17
drivers/iio/resolver/Kconfig
Normal 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
|
||||
5
drivers/iio/resolver/Makefile
Normal file
5
drivers/iio/resolver/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Makefile for Resolver/Synchro drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_AD2S1200) += ad2s1200.o
|
||||
@@ -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");
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
@@ -1,5 +0,0 @@
|
||||
#
|
||||
# Makefile for industrial I/O Light sensors
|
||||
#
|
||||
|
||||
obj-$(CONFIG_TSL2x7x) += tsl2x7x.o
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ®);
|
||||
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");
|
||||
@@ -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, ®);
|
||||
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");
|
||||
@@ -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
|
||||
@@ -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, ®);
|
||||
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");
|
||||
@@ -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, ®);
|
||||
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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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, ®);
|
||||
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");
|
||||
@@ -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
|
||||
|
||||
@@ -3,5 +3,4 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_AD2S90) += ad2s90.o
|
||||
obj-$(CONFIG_AD2S1200) += ad2s1200.o
|
||||
obj-$(CONFIG_AD2S1210) += ad2s1210.o
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 */
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user