First round of IIO new driver, functionality and cleanups for the 3.16 cycle.
New device support * AS3935 Lightning Sensor * MCP3426/7/8 support added to the existing MCP3422 ADC driver * AK8963 support in the AK8975 driver * MPU6500 support in the MPU6050 driver (the functionality that is different is mostly not supported yet in either part). Staging Graduations * AD799x ADC New functionality * ACPI enumeration for the ak8975 driver Cleanup / tweaks * Use snprintf as a matter of good practice in a few additional places. * Document *_mean_raw attributes. These have been there a while, but were undocumented. * Add an in kernel interface to get the mean values. * Bug in the length of the event info mask that by coincidence wasn't yet actually causing any problems. * itg3000 drop an unreachable return statement. * spear_adc cleanups (heading for a staging graduation but a few more issues showed up in the review of these patches). * Exynos ADC dependencies changed so it is only built when Exynos is present or COMPILE_TEST and OF are set. * tsl2583 cleanups. * Some cut and paste typos in the comments of various drivers still in staging. * Couple of minor improvements to the ST sensor drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTW8asAAoJEFSFNJnE9BaITYoP/1rONn2PS1t61CI4rtWDVZh8 SEn4EQCxRVVAdWCQQz1zY0JZeUSjuWcPi7+MJ/VNaw6efOXN0J4O+bsNfh5Asju2 88giAUuP+hmd4xccGkxaJvdXEhruRMzGugh3/6+L2XuhkJsorAhJe/63XTq+JNOp Tq6NHVmqV507wuDOguXfUQ2eDKPEFiTBUiutLJqyLOOi5zEq/X3Cnv+YMCDx4coE BwZEQnXJWLfMSvXQtbTAl1XwqvDY8bjMNwFvjRuTLN73ua0/gMe//kJV/2tm8UMF 90Fs3TPi/cc5QkvpKMC9DP8eeAMi11bRdSRN0/abEQgglCz1LzWuX5Gqpr5psrhM q1KS9JU9u4oZ8PR49c8QWjN0RtNiKiVVhCgBVcNE/2uYVwQqu0kJWylsq/m2+7jr 99qi8R979b5GoX69TKjVyr9MyGbN2x/vKWm3+UgtujqzXgu7GGdXa6NhrcPGcYjW /uH3rfW4w0rBFVEJzDXkj74n/j2WDvrukjqYgABfENfBqO14swc0nlBGGyjli0uv tUiwwS05Fax8wmuMP/wlII7Bq9XA8e+QISXHeO318svP/9SPxRuRwsd2Oo7BxXZz e6gm5i142XeiSc3KjLGEUAZ+qF7xKUfEZwIajkWZ8LIgeROfDLzNEjvVsU2Byk+0 g+XrtWm4jljKHzjV/33g =eqGz -----END PGP SIGNATURE----- Merge tag 'iio-for-3.16a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: First round of IIO new driver, functionality and cleanups for the 3.16 cycle. New device support * AS3935 Lightning Sensor * MCP3426/7/8 support added to the existing MCP3422 ADC driver * AK8963 support in the AK8975 driver * MPU6500 support in the MPU6050 driver (the functionality that is different is mostly not supported yet in either part). Staging Graduations * AD799x ADC New functionality * ACPI enumeration for the ak8975 driver Cleanup / tweaks * Use snprintf as a matter of good practice in a few additional places. * Document *_mean_raw attributes. These have been there a while, but were undocumented. * Add an in kernel interface to get the mean values. * Bug in the length of the event info mask that by coincidence wasn't yet actually causing any problems. * itg3000 drop an unreachable return statement. * spear_adc cleanups (heading for a staging graduation but a few more issues showed up in the review of these patches). * Exynos ADC dependencies changed so it is only built when Exynos is present or COMPILE_TEST and OF are set. * tsl2583 cleanups. * Some cut and paste typos in the comments of various drivers still in staging. * Couple of minor improvements to the ST sensor drivers.
This commit is contained in:
commit
d5cef008e9
|
@ -210,6 +210,14 @@ Contact: linux-iio@vger.kernel.org
|
|||
Description:
|
||||
Scaled humidity measurement in milli percent.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_X_mean_raw
|
||||
KernelVersion: 3.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Averaged raw measurement from channel X. The number of values
|
||||
used for averaging is device specific. The converting rules for
|
||||
normal raw values also applies to the averaged raw values.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
What /sys/bus/iio/devices/iio:deviceX/in_proximity_raw
|
||||
Date: March 2014
|
||||
KernelVersion: 3.15
|
||||
Contact: Matt Ranostay <mranostay@gmail.com>
|
||||
Description:
|
||||
Get the current distance in meters of storm (1km steps)
|
||||
1000-40000 = distance in meters
|
||||
|
||||
What /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
|
||||
Date: March 2014
|
||||
KernelVersion: 3.15
|
||||
Contact: Matt Ranostay <mranostay@gmail.com>
|
||||
Description:
|
||||
Show or set the gain boost of the amp, from 0-31 range.
|
||||
18 = indoors (default)
|
||||
14 = outdoors
|
|
@ -0,0 +1,28 @@
|
|||
Austrian Microsystems AS3935 Franklin lightning sensor device driver
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "ams,as3935"
|
||||
- reg: SPI chip select number for the device
|
||||
- spi-cpha: SPI Mode 1. Refer to spi/spi-bus.txt for generic SPI
|
||||
slave node bindings.
|
||||
- interrupt-parent : should be the phandle for the interrupt controller
|
||||
- interrupts : the sole interrupt generated by the device
|
||||
|
||||
Refer to interrupt-controller/interrupts.txt for generic
|
||||
interrupt client node bindings.
|
||||
|
||||
Optional properties:
|
||||
- ams,tuning-capacitor-pf: Calibration tuning capacitor stepping
|
||||
value 0 - 120pF. This will require using the calibration data from
|
||||
the manufacturer.
|
||||
|
||||
Example:
|
||||
|
||||
as3935@0 {
|
||||
compatible = "ams,as3935";
|
||||
reg = <0>;
|
||||
spi-cpha;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <16 1>;
|
||||
ams,tuning-capacitor-pf = <80>;
|
||||
};
|
|
@ -13,6 +13,7 @@ allwinner Allwinner Technology Co., Ltd.
|
|||
altr Altera Corp.
|
||||
amcc Applied Micro Circuits Corporation (APM, formally AMCC)
|
||||
amd Advanced Micro Devices (AMD), Inc.
|
||||
ams AMS AG
|
||||
amstaos AMS-Taos Inc.
|
||||
apm Applied Micro Circuits Corporation (APM)
|
||||
arm ARM Ltd.
|
||||
|
|
|
@ -74,6 +74,7 @@ if IIO_TRIGGER
|
|||
source "drivers/iio/trigger/Kconfig"
|
||||
endif #IIO_TRIGGER
|
||||
source "drivers/iio/pressure/Kconfig"
|
||||
source "drivers/iio/proximity/Kconfig"
|
||||
source "drivers/iio/temperature/Kconfig"
|
||||
|
||||
endif # IIO
|
||||
|
|
|
@ -24,5 +24,6 @@ obj-y += light/
|
|||
obj-y += magnetometer/
|
||||
obj-y += orientation/
|
||||
obj-y += pressure/
|
||||
obj-y += proximity/
|
||||
obj-y += temperature/
|
||||
obj-y += trigger/
|
||||
|
|
|
@ -459,6 +459,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &accel_info;
|
||||
|
||||
st_sensors_power_enable(indio_dev);
|
||||
|
||||
err = st_sensors_check_device_support(indio_dev,
|
||||
ARRAY_SIZE(st_accel_sensors), st_accel_sensors);
|
||||
if (err < 0)
|
||||
|
@ -496,6 +498,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev,
|
|||
if (err)
|
||||
goto st_accel_device_register_error;
|
||||
|
||||
dev_info(&indio_dev->dev, "registered accelerometer %s\n",
|
||||
indio_dev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
st_accel_device_register_error:
|
||||
|
@ -512,6 +517,8 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
|
|||
{
|
||||
struct st_sensor_data *adata = iio_priv(indio_dev);
|
||||
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (adata->get_irq_data_ready(indio_dev) > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
|
|
@ -96,6 +96,17 @@ config AD7923
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7923.
|
||||
|
||||
config AD799X
|
||||
tristate "Analog Devices AD799x ADC driver"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Analog Devices:
|
||||
ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998
|
||||
i2c analog to digital converters (ADC). Provides direct access
|
||||
via sysfs.
|
||||
|
||||
config AT91_ADC
|
||||
tristate "Atmel AT91 ADC"
|
||||
depends on ARCH_AT91
|
||||
|
@ -107,7 +118,7 @@ config AT91_ADC
|
|||
|
||||
config EXYNOS_ADC
|
||||
bool "Exynos ADC driver support"
|
||||
depends on OF
|
||||
depends on ARCH_EXYNOS || (OF && COMPILE_TEST)
|
||||
help
|
||||
Core support for the ADC block found in the Samsung EXYNOS series
|
||||
of SoCs for drivers such as the touchscreen and hwmon to use to share
|
||||
|
@ -146,11 +157,12 @@ config MCP320X
|
|||
called mcp320x.
|
||||
|
||||
config MCP3422
|
||||
tristate "Microchip Technology MCP3422/3/4 driver"
|
||||
tristate "Microchip Technology MCP3422/3/4/6/7/8 driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for Microchip Technology's MCP3422,
|
||||
MCP3423 or MCP3424 analog to digital converters.
|
||||
Say yes here to build support for Microchip Technology's
|
||||
MCP3422, MCP3423, MCP3424, MCP3426, MCP3427 or MCP3428
|
||||
analog to digital converters.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called mcp3422.
|
||||
|
|
|
@ -11,6 +11,7 @@ obj-$(CONFIG_AD7476) += ad7476.o
|
|||
obj-$(CONFIG_AD7791) += ad7791.o
|
||||
obj-$(CONFIG_AD7793) += ad7793.o
|
||||
obj-$(CONFIG_AD7887) += ad7887.o
|
||||
obj-$(CONFIG_AD799X) += ad799x.o
|
||||
obj-$(CONFIG_AT91_ADC) += at91_adc.o
|
||||
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
|
||||
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
|
||||
|
|
|
@ -37,8 +37,144 @@
|
|||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#include "ad799x.h"
|
||||
#define AD799X_CHANNEL_SHIFT 4
|
||||
#define AD799X_STORAGEBITS 16
|
||||
/*
|
||||
* AD7991, AD7995 and AD7999 defines
|
||||
*/
|
||||
|
||||
#define AD7991_REF_SEL 0x08
|
||||
#define AD7991_FLTR 0x04
|
||||
#define AD7991_BIT_TRIAL_DELAY 0x02
|
||||
#define AD7991_SAMPLE_DELAY 0x01
|
||||
|
||||
/*
|
||||
* AD7992, AD7993, AD7994, AD7997 and AD7998 defines
|
||||
*/
|
||||
|
||||
#define AD7998_FLTR 0x08
|
||||
#define AD7998_ALERT_EN 0x04
|
||||
#define AD7998_BUSY_ALERT 0x02
|
||||
#define AD7998_BUSY_ALERT_POL 0x01
|
||||
|
||||
#define AD7998_CONV_RES_REG 0x0
|
||||
#define AD7998_ALERT_STAT_REG 0x1
|
||||
#define AD7998_CONF_REG 0x2
|
||||
#define AD7998_CYCLE_TMR_REG 0x3
|
||||
|
||||
#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4)
|
||||
#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5)
|
||||
#define AD7998_HYST_REG(x) ((x) * 3 + 0x6)
|
||||
|
||||
#define AD7998_CYC_MASK 0x7
|
||||
#define AD7998_CYC_DIS 0x0
|
||||
#define AD7998_CYC_TCONF_32 0x1
|
||||
#define AD7998_CYC_TCONF_64 0x2
|
||||
#define AD7998_CYC_TCONF_128 0x3
|
||||
#define AD7998_CYC_TCONF_256 0x4
|
||||
#define AD7998_CYC_TCONF_512 0x5
|
||||
#define AD7998_CYC_TCONF_1024 0x6
|
||||
#define AD7998_CYC_TCONF_2048 0x7
|
||||
|
||||
#define AD7998_ALERT_STAT_CLEAR 0xFF
|
||||
|
||||
/*
|
||||
* AD7997 and AD7997 defines
|
||||
*/
|
||||
|
||||
#define AD7997_8_READ_SINGLE 0x80
|
||||
#define AD7997_8_READ_SEQUENCE 0x70
|
||||
/* TODO: move this into a common header */
|
||||
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
||||
|
||||
enum {
|
||||
ad7991,
|
||||
ad7995,
|
||||
ad7999,
|
||||
ad7992,
|
||||
ad7993,
|
||||
ad7994,
|
||||
ad7997,
|
||||
ad7998
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ad799x_chip_info - chip specific information
|
||||
* @channel: channel specification
|
||||
* @num_channels: number of channels
|
||||
* @monitor_mode: whether the chip supports monitor interrupts
|
||||
* @default_config: device default configuration
|
||||
* @event_attrs: pointer to the monitor event attribute group
|
||||
*/
|
||||
struct ad799x_chip_info {
|
||||
struct iio_chan_spec channel[9];
|
||||
int num_channels;
|
||||
u16 default_config;
|
||||
const struct iio_info *info;
|
||||
};
|
||||
|
||||
struct ad799x_state {
|
||||
struct i2c_client *client;
|
||||
const struct ad799x_chip_info *chip_info;
|
||||
struct regulator *reg;
|
||||
struct regulator *vref;
|
||||
unsigned id;
|
||||
u16 config;
|
||||
|
||||
u8 *rx_buf;
|
||||
unsigned int transfer_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* ad799x_trigger_handler() bh of trigger launched polling to ring buffer
|
||||
*
|
||||
* Currently there is no option in this driver to disable the saving of
|
||||
* timestamps within the ring.
|
||||
**/
|
||||
static irqreturn_t ad799x_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
int b_sent;
|
||||
u8 cmd;
|
||||
|
||||
switch (st->id) {
|
||||
case ad7991:
|
||||
case ad7995:
|
||||
case ad7999:
|
||||
cmd = st->config |
|
||||
(*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT);
|
||||
break;
|
||||
case ad7992:
|
||||
case ad7993:
|
||||
case ad7994:
|
||||
cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) |
|
||||
AD7998_CONV_RES_REG;
|
||||
break;
|
||||
case ad7997:
|
||||
case ad7998:
|
||||
cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG;
|
||||
break;
|
||||
default:
|
||||
cmd = 0;
|
||||
}
|
||||
|
||||
b_sent = i2c_smbus_read_i2c_block_data(st->client,
|
||||
cmd, st->transfer_size, st->rx_buf);
|
||||
if (b_sent < 0)
|
||||
goto out;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
|
||||
iio_get_time_ns());
|
||||
out:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* ad799x register access by I2C
|
||||
|
@ -578,7 +714,8 @@ static int ad799x_probe(struct i2c_client *client,
|
|||
indio_dev->channels = st->chip_info->channel;
|
||||
indio_dev->num_channels = st->chip_info->num_channels;
|
||||
|
||||
ret = ad799x_register_ring_funcs_and_init(indio_dev);
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&ad799x_trigger_handler, NULL);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
|
||||
|
@ -601,7 +738,7 @@ static int ad799x_probe(struct i2c_client *client,
|
|||
return 0;
|
||||
|
||||
error_cleanup_ring:
|
||||
ad799x_ring_cleanup(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
error_disable_reg:
|
||||
if (!IS_ERR(st->vref))
|
||||
regulator_disable(st->vref);
|
||||
|
@ -618,7 +755,7 @@ static int ad799x_remove(struct i2c_client *client)
|
|||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
ad799x_ring_cleanup(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
if (!IS_ERR(st->vref))
|
||||
regulator_disable(st->vref);
|
||||
if (!IS_ERR(st->reg))
|
|
@ -1,10 +1,11 @@
|
|||
/*
|
||||
* mcp3422.c - driver for the Microchip mcp3422/3/4 chip family
|
||||
* mcp3422.c - driver for the Microchip mcp3422/3/4/6/7/8 chip family
|
||||
*
|
||||
* Copyright (C) 2013, Angelo Compagnucci
|
||||
* Author: Angelo Compagnucci <angelo.compagnucci@gmail.com>
|
||||
*
|
||||
* Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf
|
||||
* http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf
|
||||
*
|
||||
* This driver exports the value of analog input voltage to sysfs, the
|
||||
* voltage unit is nV.
|
||||
|
@ -96,6 +97,7 @@ static const int mcp3422_sign_extend[4] = {
|
|||
/* Client data (each client gets its own) */
|
||||
struct mcp3422 {
|
||||
struct i2c_client *i2c;
|
||||
u8 id;
|
||||
u8 config;
|
||||
u8 pga[4];
|
||||
struct mutex lock;
|
||||
|
@ -238,6 +240,8 @@ static int mcp3422_write_raw(struct iio_dev *iio,
|
|||
temp = MCP3422_SRATE_15;
|
||||
break;
|
||||
case 3:
|
||||
if (adc->id > 4)
|
||||
return -EINVAL;
|
||||
temp = MCP3422_SRATE_3;
|
||||
break;
|
||||
default:
|
||||
|
@ -271,6 +275,17 @@ static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t mcp3422_show_samp_freqs(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev));
|
||||
|
||||
if (adc->id > 4)
|
||||
return sprintf(buf, "240 60 15\n");
|
||||
|
||||
return sprintf(buf, "240 60 15 3\n");
|
||||
}
|
||||
|
||||
static ssize_t mcp3422_show_scales(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -284,12 +299,13 @@ static ssize_t mcp3422_show_scales(struct device *dev,
|
|||
mcp3422_scales[sample_rate][3]);
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("240 60 15 3");
|
||||
static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO,
|
||||
mcp3422_show_samp_freqs, NULL, 0);
|
||||
static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO,
|
||||
mcp3422_show_scales, NULL, 0);
|
||||
|
||||
static struct attribute *mcp3422_attributes[] = {
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
@ -335,6 +351,7 @@ static int mcp3422_probe(struct i2c_client *client,
|
|||
|
||||
adc = iio_priv(indio_dev);
|
||||
adc->i2c = client;
|
||||
adc->id = (u8)(id->driver_data);
|
||||
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
|
@ -343,13 +360,16 @@ static int mcp3422_probe(struct i2c_client *client,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &mcp3422_info;
|
||||
|
||||
switch ((unsigned int)(id->driver_data)) {
|
||||
switch (adc->id) {
|
||||
case 2:
|
||||
case 3:
|
||||
case 6:
|
||||
case 7:
|
||||
indio_dev->channels = mcp3422_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels);
|
||||
break;
|
||||
case 4:
|
||||
case 8:
|
||||
indio_dev->channels = mcp3424_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels);
|
||||
break;
|
||||
|
@ -375,6 +395,9 @@ static const struct i2c_device_id mcp3422_id[] = {
|
|||
{ "mcp3422", 2 },
|
||||
{ "mcp3423", 3 },
|
||||
{ "mcp3424", 4 },
|
||||
{ "mcp3426", 6 },
|
||||
{ "mcp3427", 7 },
|
||||
{ "mcp3428", 8 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mcp3422_id);
|
||||
|
@ -399,5 +422,5 @@ static struct i2c_driver mcp3422_driver = {
|
|||
module_i2c_driver(mcp3422_driver);
|
||||
|
||||
MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>");
|
||||
MODULE_DESCRIPTION("Microchip mcp3422/3/4 driver");
|
||||
MODULE_DESCRIPTION("Microchip mcp3422/3/4/6/7/8 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
|
@ -198,6 +199,42 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
|
|||
}
|
||||
EXPORT_SYMBOL(st_sensors_set_axis_enable);
|
||||
|
||||
void st_sensors_power_enable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *pdata = iio_priv(indio_dev);
|
||||
int err;
|
||||
|
||||
/* Regulators not mandatory, but if requested we should enable them. */
|
||||
pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd");
|
||||
if (!IS_ERR(pdata->vdd)) {
|
||||
err = regulator_enable(pdata->vdd);
|
||||
if (err != 0)
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Failed to enable specified Vdd supply\n");
|
||||
}
|
||||
|
||||
pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio");
|
||||
if (!IS_ERR(pdata->vdd_io)) {
|
||||
err = regulator_enable(pdata->vdd_io);
|
||||
if (err != 0)
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Failed to enable specified Vdd_IO supply\n");
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_power_enable);
|
||||
|
||||
void st_sensors_power_disable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *pdata = iio_priv(indio_dev);
|
||||
|
||||
if (!IS_ERR(pdata->vdd))
|
||||
regulator_disable(pdata->vdd);
|
||||
|
||||
if (!IS_ERR(pdata->vdd_io))
|
||||
regulator_disable(pdata->vdd_io);
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_power_disable);
|
||||
|
||||
static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
|
||||
struct st_sensors_platform_data *pdata)
|
||||
{
|
||||
|
|
|
@ -110,8 +110,6 @@ static int itg3200_read_raw(struct iio_dev *indio_dev,
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t itg3200_read_frequency(struct device *dev,
|
||||
|
|
|
@ -311,6 +311,8 @@ int st_gyro_common_probe(struct iio_dev *indio_dev,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &gyro_info;
|
||||
|
||||
st_sensors_power_enable(indio_dev);
|
||||
|
||||
err = st_sensors_check_device_support(indio_dev,
|
||||
ARRAY_SIZE(st_gyro_sensors), st_gyro_sensors);
|
||||
if (err < 0)
|
||||
|
@ -344,6 +346,9 @@ int st_gyro_common_probe(struct iio_dev *indio_dev,
|
|||
if (err)
|
||||
goto st_gyro_device_register_error;
|
||||
|
||||
dev_info(&indio_dev->dev, "registered gyroscope %s\n",
|
||||
indio_dev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
st_gyro_device_register_error:
|
||||
|
@ -360,6 +365,8 @@ void st_gyro_common_remove(struct iio_dev *indio_dev)
|
|||
{
|
||||
struct st_sensor_data *gdata = iio_priv(indio_dev);
|
||||
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (gdata->get_irq_data_ready(indio_dev) > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
|
|
@ -9,6 +9,8 @@ config INV_MPU6050_IIO
|
|||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
This driver supports the Invensense MPU6050 devices.
|
||||
This driver can also support MPU6500 in MPU6050 compatibility mode
|
||||
and also in MPU6500 mode with some limitations.
|
||||
It is a gyroscope/accelerometer combo device.
|
||||
This driver can be built as a module. The module will be called
|
||||
inv-mpu6050.
|
||||
|
|
|
@ -764,6 +764,7 @@ static SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume);
|
|||
*/
|
||||
static const struct i2c_device_id inv_mpu_id[] = {
|
||||
{"mpu6050", INV_MPU6050},
|
||||
{"mpu6500", INV_MPU6500},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ struct inv_mpu6050_reg_map {
|
|||
/*device enum */
|
||||
enum inv_devices {
|
||||
INV_MPU6050,
|
||||
INV_MPU6500,
|
||||
INV_NUM_PARTS
|
||||
};
|
||||
|
||||
|
|
|
@ -340,7 +340,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev,
|
|||
else if (i >= e->num_items)
|
||||
return -EINVAL;
|
||||
|
||||
return sprintf(buf, "%s\n", e->items[i]);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_enum_read);
|
||||
|
||||
|
@ -716,6 +716,8 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
|
|||
int i, ret, attrcount = 0;
|
||||
|
||||
for_each_set_bit(i, infomask, sizeof(infomask)*8) {
|
||||
if (i >= ARRAY_SIZE(iio_chan_info_postfix))
|
||||
return -EINVAL;
|
||||
ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
|
||||
chan,
|
||||
&iio_read_channel_info,
|
||||
|
@ -820,7 +822,7 @@ static ssize_t iio_show_dev_name(struct device *dev,
|
|||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
return sprintf(buf, "%s\n", indio_dev->name);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->name);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
|
||||
|
|
|
@ -321,7 +321,9 @@ static int iio_device_add_event(struct iio_dev *indio_dev,
|
|||
char *postfix;
|
||||
int ret;
|
||||
|
||||
for_each_set_bit(i, mask, sizeof(*mask)) {
|
||||
for_each_set_bit(i, mask, sizeof(*mask)*8) {
|
||||
if (i >= ARRAY_SIZE(iio_ev_info_text))
|
||||
return -EINVAL;
|
||||
postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
|
||||
iio_ev_type_text[type], iio_ev_dir_text[dir],
|
||||
iio_ev_info_text[i]);
|
||||
|
|
|
@ -443,6 +443,24 @@ err_unlock:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(iio_read_channel_raw);
|
||||
|
||||
int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chan->indio_dev->info_exist_lock);
|
||||
if (chan->indio_dev->info == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW);
|
||||
err_unlock:
|
||||
mutex_unlock(&chan->indio_dev->info_exist_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_read_channel_average_raw);
|
||||
|
||||
static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
|
||||
int raw, int *processed, unsigned int scale)
|
||||
{
|
||||
|
|
|
@ -11,7 +11,8 @@ config AK8975
|
|||
depends on GPIOLIB
|
||||
help
|
||||
Say yes here to build support for Asahi Kasei AK8975 3-Axis
|
||||
Magnetometer.
|
||||
Magnetometer. This driver can also support AK8963, if i2c
|
||||
device name is identified as ak8963.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called ak8975.
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
@ -85,7 +86,14 @@
|
|||
#define AK8975_MAX_CONVERSION_TIMEOUT 500
|
||||
#define AK8975_CONVERSION_DONE_POLL_TIME 10
|
||||
#define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000)
|
||||
#define RAW_TO_GAUSS(asa) ((((asa) + 128) * 3000) / 256)
|
||||
#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
|
||||
#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
|
||||
|
||||
/* Compatible Asahi Kasei Compass parts */
|
||||
enum asahi_compass_chipset {
|
||||
AK8975,
|
||||
AK8963,
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-instance context data for the device.
|
||||
|
@ -101,6 +109,7 @@ struct ak8975_data {
|
|||
int eoc_irq;
|
||||
wait_queue_head_t data_ready_queue;
|
||||
unsigned long flags;
|
||||
enum asahi_compass_chipset chipset;
|
||||
};
|
||||
|
||||
static const int ak8975_index_to_reg[] = {
|
||||
|
@ -272,9 +281,21 @@ static int ak8975_setup(struct i2c_client *client)
|
|||
* Since ASA doesn't change, we cache the resultant scale factor into the
|
||||
* device context in ak8975_setup().
|
||||
*/
|
||||
data->raw_to_gauss[0] = RAW_TO_GAUSS(data->asa[0]);
|
||||
data->raw_to_gauss[1] = RAW_TO_GAUSS(data->asa[1]);
|
||||
data->raw_to_gauss[2] = RAW_TO_GAUSS(data->asa[2]);
|
||||
if (data->chipset == AK8963) {
|
||||
/*
|
||||
* H range is +-8190 and magnetometer range is +-4912.
|
||||
* So HuT using the above explanation for 8975,
|
||||
* 4912/8190 = ~ 6/10.
|
||||
* So the Hadj should use 6/10 instead of 3/10.
|
||||
*/
|
||||
data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
|
||||
data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
|
||||
data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
|
||||
} else {
|
||||
data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
|
||||
data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
|
||||
data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -455,6 +476,27 @@ static const struct iio_info ak8975_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct acpi_device_id ak_acpi_match[] = {
|
||||
{"AK8975", AK8975},
|
||||
{"AK8963", AK8963},
|
||||
{"INVN6500", AK8963},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
|
||||
|
||||
static char *ak8975_match_acpi_device(struct device *dev,
|
||||
enum asahi_compass_chipset *chipset)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
|
||||
id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!id)
|
||||
return NULL;
|
||||
*chipset = (int)id->driver_data;
|
||||
|
||||
return (char *)dev_name(dev);
|
||||
}
|
||||
|
||||
static int ak8975_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -462,6 +504,7 @@ static int ak8975_probe(struct i2c_client *client,
|
|||
struct iio_dev *indio_dev;
|
||||
int eoc_gpio;
|
||||
int err;
|
||||
char *name = NULL;
|
||||
|
||||
/* Grab and set up the supplied GPIO. */
|
||||
if (client->dev.platform_data)
|
||||
|
@ -499,6 +542,19 @@ static int ak8975_probe(struct i2c_client *client,
|
|||
data->eoc_gpio = eoc_gpio;
|
||||
data->eoc_irq = 0;
|
||||
|
||||
/* id will be NULL when enumerated via ACPI */
|
||||
if (id) {
|
||||
data->chipset =
|
||||
(enum asahi_compass_chipset)(id->driver_data);
|
||||
name = (char *) id->name;
|
||||
} else if (ACPI_HANDLE(&client->dev))
|
||||
name = ak8975_match_acpi_device(&client->dev, &data->chipset);
|
||||
else {
|
||||
err = -ENOSYS;
|
||||
goto exit_free_iio;
|
||||
}
|
||||
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
|
||||
|
||||
/* Perform some basic start-of-day setup of the device. */
|
||||
err = ak8975_setup(client);
|
||||
if (err < 0) {
|
||||
|
@ -515,7 +571,7 @@ static int ak8975_probe(struct i2c_client *client,
|
|||
indio_dev->info = &ak8975_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
indio_dev->name = name;
|
||||
err = iio_device_register(indio_dev);
|
||||
if (err < 0)
|
||||
goto exit_free_iio;
|
||||
|
@ -552,7 +608,8 @@ static int ak8975_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id ak8975_id[] = {
|
||||
{"ak8975", 0},
|
||||
{"ak8975", AK8975},
|
||||
{"ak8963", AK8963},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -569,6 +626,7 @@ static struct i2c_driver ak8975_driver = {
|
|||
.driver = {
|
||||
.name = "ak8975",
|
||||
.of_match_table = ak8975_of_match,
|
||||
.acpi_match_table = ACPI_PTR(ak_acpi_match),
|
||||
},
|
||||
.probe = ak8975_probe,
|
||||
.remove = ak8975_remove,
|
||||
|
|
|
@ -355,6 +355,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &magn_info;
|
||||
|
||||
st_sensors_power_enable(indio_dev);
|
||||
|
||||
err = st_sensors_check_device_support(indio_dev,
|
||||
ARRAY_SIZE(st_magn_sensors), st_magn_sensors);
|
||||
if (err < 0)
|
||||
|
@ -387,6 +389,9 @@ int st_magn_common_probe(struct iio_dev *indio_dev,
|
|||
if (err)
|
||||
goto st_magn_device_register_error;
|
||||
|
||||
dev_info(&indio_dev->dev, "registered magnetometer %s\n",
|
||||
indio_dev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
st_magn_device_register_error:
|
||||
|
@ -403,6 +408,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev)
|
|||
{
|
||||
struct st_sensor_data *mdata = iio_priv(indio_dev);
|
||||
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (mdata->get_irq_data_ready(indio_dev) > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
|
@ -387,40 +386,6 @@ static const struct iio_trigger_ops st_press_trigger_ops = {
|
|||
#define ST_PRESS_TRIGGER_OPS NULL
|
||||
#endif
|
||||
|
||||
static void st_press_power_enable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *pdata = iio_priv(indio_dev);
|
||||
int err;
|
||||
|
||||
/* Regulators not mandatory, but if requested we should enable them. */
|
||||
pdata->vdd = devm_regulator_get_optional(&indio_dev->dev, "vdd");
|
||||
if (!IS_ERR(pdata->vdd)) {
|
||||
err = regulator_enable(pdata->vdd);
|
||||
if (err != 0)
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Failed to enable specified Vdd supply\n");
|
||||
}
|
||||
|
||||
pdata->vdd_io = devm_regulator_get_optional(&indio_dev->dev, "vddio");
|
||||
if (!IS_ERR(pdata->vdd_io)) {
|
||||
err = regulator_enable(pdata->vdd_io);
|
||||
if (err != 0)
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Failed to enable specified Vdd_IO supply\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void st_press_power_disable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *pdata = iio_priv(indio_dev);
|
||||
|
||||
if (!IS_ERR(pdata->vdd))
|
||||
regulator_disable(pdata->vdd);
|
||||
|
||||
if (!IS_ERR(pdata->vdd_io))
|
||||
regulator_disable(pdata->vdd_io);
|
||||
}
|
||||
|
||||
int st_press_common_probe(struct iio_dev *indio_dev,
|
||||
struct st_sensors_platform_data *plat_data)
|
||||
{
|
||||
|
@ -431,7 +396,7 @@ int st_press_common_probe(struct iio_dev *indio_dev,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &press_info;
|
||||
|
||||
st_press_power_enable(indio_dev);
|
||||
st_sensors_power_enable(indio_dev);
|
||||
|
||||
err = st_sensors_check_device_support(indio_dev,
|
||||
ARRAY_SIZE(st_press_sensors),
|
||||
|
@ -474,6 +439,9 @@ int st_press_common_probe(struct iio_dev *indio_dev,
|
|||
if (err)
|
||||
goto st_press_device_register_error;
|
||||
|
||||
dev_info(&indio_dev->dev, "registered pressure sensor %s\n",
|
||||
indio_dev->name);
|
||||
|
||||
return err;
|
||||
|
||||
st_press_device_register_error:
|
||||
|
@ -490,7 +458,7 @@ void st_press_common_remove(struct iio_dev *indio_dev)
|
|||
{
|
||||
struct st_sensor_data *pdata = iio_priv(indio_dev);
|
||||
|
||||
st_press_power_disable(indio_dev);
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (pdata->get_irq_data_ready(indio_dev) > 0)
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
# Proximity sensors
|
||||
#
|
||||
|
||||
menu "Lightning sensors"
|
||||
|
||||
config AS3935
|
||||
tristate "AS3935 Franklin lightning sensor"
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
depends on SPI
|
||||
help
|
||||
Say Y here to build SPI interface support for the Austrian
|
||||
Microsystems AS3935 lightning detection sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called as3935
|
||||
|
||||
endmenu
|
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
# Makefile for IIO proximity sensors
|
||||
#
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_AS3935) += as3935.o
|
|
@ -0,0 +1,456 @@
|
|||
/*
|
||||
* as3935.c - Support for AS3935 Franklin lightning sensor
|
||||
*
|
||||
* Copyright (C) 2014 Matt Ranostay <mranostay@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
|
||||
#define AS3935_AFE_GAIN 0x00
|
||||
#define AS3935_AFE_MASK 0x3F
|
||||
#define AS3935_AFE_GAIN_MAX 0x1F
|
||||
#define AS3935_AFE_PWR_BIT BIT(0)
|
||||
|
||||
#define AS3935_INT 0x03
|
||||
#define AS3935_INT_MASK 0x07
|
||||
#define AS3935_EVENT_INT BIT(3)
|
||||
#define AS3935_NOISE_INT BIT(1)
|
||||
|
||||
#define AS3935_DATA 0x07
|
||||
#define AS3935_DATA_MASK 0x3F
|
||||
|
||||
#define AS3935_TUNE_CAP 0x08
|
||||
#define AS3935_CALIBRATE 0x3D
|
||||
|
||||
#define AS3935_WRITE_DATA BIT(15)
|
||||
#define AS3935_READ_DATA BIT(14)
|
||||
#define AS3935_ADDRESS(x) ((x) << 8)
|
||||
|
||||
#define MAX_PF_CAP 120
|
||||
#define TUNE_CAP_DIV 8
|
||||
|
||||
struct as3935_state {
|
||||
struct spi_device *spi;
|
||||
struct iio_trigger *trig;
|
||||
struct mutex lock;
|
||||
struct delayed_work work;
|
||||
|
||||
u32 tune_cap;
|
||||
u8 buf[2] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec as3935_channels[] = {
|
||||
{
|
||||
.type = IIO_PROXIMITY,
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 6,
|
||||
.storagebits = 8,
|
||||
},
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
};
|
||||
|
||||
static int as3935_read(struct as3935_state *st, unsigned int reg, int *val)
|
||||
{
|
||||
u8 cmd;
|
||||
int ret;
|
||||
|
||||
cmd = (AS3935_READ_DATA | AS3935_ADDRESS(reg)) >> 8;
|
||||
ret = spi_w8r8(st->spi, cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int as3935_write(struct as3935_state *st,
|
||||
unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
u8 *buf = st->buf;
|
||||
|
||||
buf[0] = (AS3935_WRITE_DATA | AS3935_ADDRESS(reg)) >> 8;
|
||||
buf[1] = val;
|
||||
|
||||
return spi_write(st->spi, buf, 2);
|
||||
};
|
||||
|
||||
static ssize_t as3935_sensor_sensitivity_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
|
||||
int val, ret;
|
||||
|
||||
ret = as3935_read(st, AS3935_AFE_GAIN, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
val = (val & AS3935_AFE_MASK) >> 1;
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
};
|
||||
|
||||
static ssize_t as3935_sensor_sensitivity_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul((const char *) buf, 10, &val);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (val > AS3935_AFE_GAIN_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
as3935_write(st, AS3935_AFE_GAIN, val << 1);
|
||||
|
||||
return len;
|
||||
};
|
||||
|
||||
static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
|
||||
as3935_sensor_sensitivity_show, as3935_sensor_sensitivity_store, 0);
|
||||
|
||||
|
||||
static struct attribute *as3935_attributes[] = {
|
||||
&iio_dev_attr_sensor_sensitivity.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group as3935_attribute_group = {
|
||||
.attrs = as3935_attributes,
|
||||
};
|
||||
|
||||
static int as3935_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
int *val2,
|
||||
long m)
|
||||
{
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
|
||||
switch (m) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
*val2 = 0;
|
||||
ret = as3935_read(st, AS3935_DATA, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (m == IIO_CHAN_INFO_RAW)
|
||||
return IIO_VAL_INT;
|
||||
|
||||
/* storm out of range */
|
||||
if (*val == AS3935_DATA_MASK)
|
||||
return -EINVAL;
|
||||
*val *= 1000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static const struct iio_info as3935_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.attrs = &as3935_attribute_group,
|
||||
.read_raw = &as3935_read_raw,
|
||||
};
|
||||
|
||||
static irqreturn_t as3935_trigger_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_poll_func *pf = private;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
int val, ret;
|
||||
|
||||
ret = as3935_read(st, AS3935_DATA, &val);
|
||||
if (ret)
|
||||
goto err_read;
|
||||
val &= AS3935_DATA_MASK;
|
||||
val *= 1000;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &val, pf->timestamp);
|
||||
err_read:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
};
|
||||
|
||||
static const struct iio_trigger_ops iio_interrupt_trigger_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void as3935_event_work(struct work_struct *work)
|
||||
{
|
||||
struct as3935_state *st;
|
||||
int val;
|
||||
|
||||
st = container_of(work, struct as3935_state, work.work);
|
||||
|
||||
as3935_read(st, AS3935_INT, &val);
|
||||
val &= AS3935_INT_MASK;
|
||||
|
||||
switch (val) {
|
||||
case AS3935_EVENT_INT:
|
||||
iio_trigger_poll(st->trig, iio_get_time_ns());
|
||||
break;
|
||||
case AS3935_NOISE_INT:
|
||||
dev_warn(&st->spi->dev, "noise level is too high");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
static irqreturn_t as3935_interrupt_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
|
||||
/*
|
||||
* Delay work for >2 milliseconds after an interrupt to allow
|
||||
* estimated distance to recalculated.
|
||||
*/
|
||||
|
||||
schedule_delayed_work(&st->work, msecs_to_jiffies(3));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void calibrate_as3935(struct as3935_state *st)
|
||||
{
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
/* mask disturber interrupt bit */
|
||||
as3935_write(st, AS3935_INT, BIT(5));
|
||||
|
||||
as3935_write(st, AS3935_CALIBRATE, 0x96);
|
||||
as3935_write(st, AS3935_TUNE_CAP,
|
||||
BIT(5) | (st->tune_cap / TUNE_CAP_DIV));
|
||||
|
||||
mdelay(2);
|
||||
as3935_write(st, AS3935_TUNE_CAP, (st->tune_cap / TUNE_CAP_DIV));
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int as3935_suspend(struct spi_device *spi, pm_message_t msg)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
int val, ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
ret = as3935_read(st, AS3935_AFE_GAIN, &val);
|
||||
if (ret)
|
||||
goto err_suspend;
|
||||
val |= AS3935_AFE_PWR_BIT;
|
||||
|
||||
ret = as3935_write(st, AS3935_AFE_GAIN, val);
|
||||
|
||||
err_suspend:
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as3935_resume(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
int val, ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
ret = as3935_read(st, AS3935_AFE_GAIN, &val);
|
||||
if (ret)
|
||||
goto err_resume;
|
||||
val &= ~AS3935_AFE_PWR_BIT;
|
||||
ret = as3935_write(st, AS3935_AFE_GAIN, val);
|
||||
|
||||
err_resume:
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#define as3935_suspend NULL
|
||||
#define as3935_resume NULL
|
||||
#endif
|
||||
|
||||
static int as3935_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct iio_trigger *trig;
|
||||
struct as3935_state *st;
|
||||
struct device_node *np = spi->dev.of_node;
|
||||
int ret;
|
||||
|
||||
/* Be sure lightning event interrupt is specified */
|
||||
if (!spi->irq) {
|
||||
dev_err(&spi->dev, "unable to get event interrupt\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
st->spi = spi;
|
||||
st->tune_cap = 0;
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
mutex_init(&st->lock);
|
||||
INIT_DELAYED_WORK(&st->work, as3935_event_work);
|
||||
|
||||
ret = of_property_read_u32(np,
|
||||
"ams,tuning-capacitor-pf", &st->tune_cap);
|
||||
if (ret) {
|
||||
st->tune_cap = 0;
|
||||
dev_warn(&spi->dev,
|
||||
"no tuning-capacitor-pf set, defaulting to %d",
|
||||
st->tune_cap);
|
||||
}
|
||||
|
||||
if (st->tune_cap > MAX_PF_CAP) {
|
||||
dev_err(&spi->dev,
|
||||
"wrong tuning-capacitor-pf setting of %d\n",
|
||||
st->tune_cap);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->channels = as3935_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(as3935_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &as3935_info;
|
||||
|
||||
trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
|
||||
indio_dev->name, indio_dev->id);
|
||||
|
||||
if (!trig)
|
||||
return -ENOMEM;
|
||||
|
||||
st->trig = trig;
|
||||
trig->dev.parent = indio_dev->dev.parent;
|
||||
iio_trigger_set_drvdata(trig, indio_dev);
|
||||
trig->ops = &iio_interrupt_trigger_ops;
|
||||
|
||||
ret = iio_trigger_register(trig);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "failed to register trigger\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&as3935_trigger_handler, NULL);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "cannot setup iio trigger\n");
|
||||
goto unregister_trigger;
|
||||
}
|
||||
|
||||
calibrate_as3935(st);
|
||||
|
||||
ret = devm_request_irq(&spi->dev, spi->irq,
|
||||
&as3935_interrupt_handler,
|
||||
IRQF_TRIGGER_RISING,
|
||||
dev_name(&spi->dev),
|
||||
indio_dev);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "unable to request irq\n");
|
||||
goto unregister_buffer;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "unable to register device\n");
|
||||
goto unregister_buffer;
|
||||
}
|
||||
return 0;
|
||||
|
||||
unregister_buffer:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
unregister_trigger:
|
||||
iio_trigger_unregister(st->trig);
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
static int as3935_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
iio_trigger_unregister(st->trig);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static const struct spi_device_id as3935_id[] = {
|
||||
{"as3935", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, as3935_id);
|
||||
|
||||
static struct spi_driver as3935_driver = {
|
||||
.driver = {
|
||||
.name = "as3935",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = as3935_probe,
|
||||
.remove = as3935_remove,
|
||||
.id_table = as3935_id,
|
||||
.suspend = as3935_suspend,
|
||||
.resume = as3935_resume,
|
||||
};
|
||||
module_spi_driver(as3935_driver);
|
||||
|
||||
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
|
||||
MODULE_DESCRIPTION("AS3935 lightning sensor");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("spi:as3935");
|
|
@ -37,26 +37,6 @@ config AD7606_IFACE_SPI
|
|||
Say yes here to include parallel interface support on the AD7606
|
||||
ADC driver.
|
||||
|
||||
config AD799X
|
||||
tristate "Analog Devices AD799x ADC driver"
|
||||
depends on I2C
|
||||
select IIO_TRIGGER if IIO_BUFFER
|
||||
select AD799X_RING_BUFFER
|
||||
help
|
||||
Say yes here to build support for Analog Devices:
|
||||
ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998
|
||||
i2c analog to digital converters (ADC). Provides direct access
|
||||
via sysfs.
|
||||
|
||||
config AD799X_RING_BUFFER
|
||||
bool "Analog Devices AD799x: use ring buffer"
|
||||
depends on AD799X
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to include ring buffer support in the AD799X
|
||||
ADC driver.
|
||||
|
||||
config AD7780
|
||||
tristate "Analog Devices AD7780 and similar ADCs driver"
|
||||
depends on SPI
|
||||
|
|
|
@ -8,10 +8,6 @@ ad7606-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
|
|||
ad7606-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
|
||||
obj-$(CONFIG_AD7606) += ad7606.o
|
||||
|
||||
ad799x-y := ad799x_core.o
|
||||
ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o
|
||||
obj-$(CONFIG_AD799X) += ad799x.o
|
||||
|
||||
obj-$(CONFIG_AD7291) += ad7291.o
|
||||
obj-$(CONFIG_AD7780) += ad7780.o
|
||||
obj-$(CONFIG_AD7816) += ad7816.o
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* struct ad7606_platform_data - platform/board specifc information
|
||||
* struct ad7606_platform_data - platform/board specific information
|
||||
* @default_os: default oversampling value {0, 2, 4, 8, 16, 32, 64}
|
||||
* @default_range: default range +/-{5000, 10000} mVolt
|
||||
* @gpio_convst: number of gpio connected to the CONVST pin
|
||||
|
@ -41,7 +41,7 @@ struct ad7606_platform_data {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct ad7606_chip_info - chip specifc information
|
||||
* struct ad7606_chip_info - chip specific information
|
||||
* @name: identification string for chip
|
||||
* @int_vref_mv: the internal reference voltage
|
||||
* @channels: channel specification
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
|
||||
/*
|
||||
* struct ad7816_chip_info - chip specifc information
|
||||
* struct ad7816_chip_info - chip specific information
|
||||
*/
|
||||
|
||||
struct ad7816_chip_info {
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc.
|
||||
* Copyright (C) 2008-2010 Jonathan Cameron
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ad799x.h
|
||||
*/
|
||||
|
||||
#ifndef _AD799X_H_
|
||||
#define _AD799X_H_
|
||||
|
||||
#define AD799X_CHANNEL_SHIFT 4
|
||||
#define AD799X_STORAGEBITS 16
|
||||
/*
|
||||
* AD7991, AD7995 and AD7999 defines
|
||||
*/
|
||||
|
||||
#define AD7991_REF_SEL 0x08
|
||||
#define AD7991_FLTR 0x04
|
||||
#define AD7991_BIT_TRIAL_DELAY 0x02
|
||||
#define AD7991_SAMPLE_DELAY 0x01
|
||||
|
||||
/*
|
||||
* AD7992, AD7993, AD7994, AD7997 and AD7998 defines
|
||||
*/
|
||||
|
||||
#define AD7998_FLTR 0x08
|
||||
#define AD7998_ALERT_EN 0x04
|
||||
#define AD7998_BUSY_ALERT 0x02
|
||||
#define AD7998_BUSY_ALERT_POL 0x01
|
||||
|
||||
#define AD7998_CONV_RES_REG 0x0
|
||||
#define AD7998_ALERT_STAT_REG 0x1
|
||||
#define AD7998_CONF_REG 0x2
|
||||
#define AD7998_CYCLE_TMR_REG 0x3
|
||||
|
||||
#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4)
|
||||
#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5)
|
||||
#define AD7998_HYST_REG(x) ((x) * 3 + 0x6)
|
||||
|
||||
#define AD7998_CYC_MASK 0x7
|
||||
#define AD7998_CYC_DIS 0x0
|
||||
#define AD7998_CYC_TCONF_32 0x1
|
||||
#define AD7998_CYC_TCONF_64 0x2
|
||||
#define AD7998_CYC_TCONF_128 0x3
|
||||
#define AD7998_CYC_TCONF_256 0x4
|
||||
#define AD7998_CYC_TCONF_512 0x5
|
||||
#define AD7998_CYC_TCONF_1024 0x6
|
||||
#define AD7998_CYC_TCONF_2048 0x7
|
||||
|
||||
#define AD7998_ALERT_STAT_CLEAR 0xFF
|
||||
|
||||
/*
|
||||
* AD7997 and AD7997 defines
|
||||
*/
|
||||
|
||||
#define AD7997_8_READ_SINGLE 0x80
|
||||
#define AD7997_8_READ_SEQUENCE 0x70
|
||||
/* TODO: move this into a common header */
|
||||
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
||||
|
||||
enum {
|
||||
ad7991,
|
||||
ad7995,
|
||||
ad7999,
|
||||
ad7992,
|
||||
ad7993,
|
||||
ad7994,
|
||||
ad7997,
|
||||
ad7998
|
||||
};
|
||||
|
||||
struct ad799x_state;
|
||||
|
||||
/**
|
||||
* struct ad799x_chip_info - chip specifc information
|
||||
* @channel: channel specification
|
||||
* @num_channels: number of channels
|
||||
* @monitor_mode: whether the chip supports monitor interrupts
|
||||
* @default_config: device default configuration
|
||||
* @event_attrs: pointer to the monitor event attribute group
|
||||
*/
|
||||
|
||||
struct ad799x_chip_info {
|
||||
struct iio_chan_spec channel[9];
|
||||
int num_channels;
|
||||
u16 default_config;
|
||||
const struct iio_info *info;
|
||||
};
|
||||
|
||||
struct ad799x_state {
|
||||
struct i2c_client *client;
|
||||
const struct ad799x_chip_info *chip_info;
|
||||
struct regulator *reg;
|
||||
struct regulator *vref;
|
||||
unsigned id;
|
||||
u16 config;
|
||||
|
||||
u8 *rx_buf;
|
||||
unsigned int transfer_size;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_AD799X_RING_BUFFER
|
||||
int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev);
|
||||
void ad799x_ring_cleanup(struct iio_dev *indio_dev);
|
||||
#else /* CONFIG_AD799X_RING_BUFFER */
|
||||
|
||||
static inline int
|
||||
ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ad799x_ring_cleanup(struct iio_dev *indio_dev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_AD799X_RING_BUFFER */
|
||||
#endif /* _AD799X_H_ */
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2012 Michael Hennerich, Analog Devices Inc.
|
||||
* Copyright (C) 2008-2010 Jonathan Cameron
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ad799x_ring.c
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#include "ad799x.h"
|
||||
|
||||
/**
|
||||
* ad799x_trigger_handler() bh of trigger launched polling to ring buffer
|
||||
*
|
||||
* Currently there is no option in this driver to disable the saving of
|
||||
* timestamps within the ring.
|
||||
**/
|
||||
|
||||
static irqreturn_t ad799x_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
int b_sent;
|
||||
u8 cmd;
|
||||
|
||||
switch (st->id) {
|
||||
case ad7991:
|
||||
case ad7995:
|
||||
case ad7999:
|
||||
cmd = st->config |
|
||||
(*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT);
|
||||
break;
|
||||
case ad7992:
|
||||
case ad7993:
|
||||
case ad7994:
|
||||
cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) |
|
||||
AD7998_CONV_RES_REG;
|
||||
break;
|
||||
case ad7997:
|
||||
case ad7998:
|
||||
cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG;
|
||||
break;
|
||||
default:
|
||||
cmd = 0;
|
||||
}
|
||||
|
||||
b_sent = i2c_smbus_read_i2c_block_data(st->client,
|
||||
cmd, st->transfer_size, st->rx_buf);
|
||||
if (b_sent < 0)
|
||||
goto out;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
|
||||
iio_get_time_ns());
|
||||
out:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
|
||||
{
|
||||
return iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&ad799x_trigger_handler, NULL);
|
||||
}
|
||||
|
||||
void ad799x_ring_cleanup(struct iio_dev *indio_dev)
|
||||
{
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
}
|
|
@ -22,39 +22,36 @@
|
|||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
/*
|
||||
* SPEAR registers definitions
|
||||
*/
|
||||
|
||||
#define SCAN_RATE_LO(x) ((x) & 0xFFFF)
|
||||
#define SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF)
|
||||
#define CLK_LOW(x) (((x) & 0xf) << 0)
|
||||
#define CLK_HIGH(x) (((x) & 0xf) << 4)
|
||||
/* SPEAR registers definitions */
|
||||
#define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF)
|
||||
#define SPEAR600_ADC_SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF)
|
||||
#define SPEAR_ADC_CLK_LOW(x) (((x) & 0xf) << 0)
|
||||
#define SPEAR_ADC_CLK_HIGH(x) (((x) & 0xf) << 4)
|
||||
|
||||
/* Bit definitions for SPEAR_ADC_STATUS */
|
||||
#define START_CONVERSION (1 << 0)
|
||||
#define CHANNEL_NUM(x) ((x) << 1)
|
||||
#define ADC_ENABLE (1 << 4)
|
||||
#define AVG_SAMPLE(x) ((x) << 5)
|
||||
#define VREF_INTERNAL (1 << 9)
|
||||
#define SPEAR_ADC_STATUS_START_CONVERSION (1 << 0)
|
||||
#define SPEAR_ADC_STATUS_CHANNEL_NUM(x) ((x) << 1)
|
||||
#define SPEAR_ADC_STATUS_ADC_ENABLE (1 << 4)
|
||||
#define SPEAR_ADC_STATUS_AVG_SAMPLE(x) ((x) << 5)
|
||||
#define SPEAR_ADC_STATUS_VREF_INTERNAL (1 << 9)
|
||||
|
||||
#define DATA_MASK 0x03ff
|
||||
#define DATA_BITS 10
|
||||
#define SPEAR_ADC_DATA_MASK 0x03ff
|
||||
#define SPEAR_ADC_DATA_BITS 10
|
||||
|
||||
#define MOD_NAME "spear-adc"
|
||||
#define SPEAR_ADC_MOD_NAME "spear-adc"
|
||||
|
||||
#define ADC_CHANNEL_NUM 8
|
||||
#define SPEAR_ADC_CHANNEL_NUM 8
|
||||
|
||||
#define CLK_MIN 2500000
|
||||
#define CLK_MAX 20000000
|
||||
#define SPEAR_ADC_CLK_MIN 2500000
|
||||
#define SPEAR_ADC_CLK_MAX 20000000
|
||||
|
||||
struct adc_regs_spear3xx {
|
||||
u32 status;
|
||||
u32 average;
|
||||
u32 scan_rate;
|
||||
u32 clk; /* Not avail for 1340 & 1310 */
|
||||
u32 ch_ctrl[ADC_CHANNEL_NUM];
|
||||
u32 ch_data[ADC_CHANNEL_NUM];
|
||||
u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM];
|
||||
u32 ch_data[SPEAR_ADC_CHANNEL_NUM];
|
||||
};
|
||||
|
||||
struct chan_data {
|
||||
|
@ -66,14 +63,14 @@ struct adc_regs_spear6xx {
|
|||
u32 status;
|
||||
u32 pad[2];
|
||||
u32 clk;
|
||||
u32 ch_ctrl[ADC_CHANNEL_NUM];
|
||||
struct chan_data ch_data[ADC_CHANNEL_NUM];
|
||||
u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM];
|
||||
struct chan_data ch_data[SPEAR_ADC_CHANNEL_NUM];
|
||||
u32 scan_rate_lo;
|
||||
u32 scan_rate_hi;
|
||||
struct chan_data average;
|
||||
};
|
||||
|
||||
struct spear_adc_info {
|
||||
struct spear_adc_state {
|
||||
struct device_node *np;
|
||||
struct adc_regs_spear3xx __iomem *adc_base_spear3xx;
|
||||
struct adc_regs_spear6xx __iomem *adc_base_spear6xx;
|
||||
|
@ -91,100 +88,129 @@ struct spear_adc_info {
|
|||
* static inline functions, because of different register offsets
|
||||
* on different SoC variants (SPEAr300 vs SPEAr600 etc).
|
||||
*/
|
||||
static void spear_adc_set_status(struct spear_adc_info *info, u32 val)
|
||||
static void spear_adc_set_status(struct spear_adc_state *st, u32 val)
|
||||
{
|
||||
__raw_writel(val, &info->adc_base_spear6xx->status);
|
||||
__raw_writel(val, &st->adc_base_spear6xx->status);
|
||||
}
|
||||
|
||||
static void spear_adc_set_clk(struct spear_adc_info *info, u32 val)
|
||||
static void spear_adc_set_clk(struct spear_adc_state *st, u32 val)
|
||||
{
|
||||
u32 clk_high, clk_low, count;
|
||||
u32 apb_clk = clk_get_rate(info->clk);
|
||||
u32 apb_clk = clk_get_rate(st->clk);
|
||||
|
||||
count = (apb_clk + val - 1) / val;
|
||||
clk_low = count / 2;
|
||||
clk_high = count - clk_low;
|
||||
info->current_clk = apb_clk / count;
|
||||
st->current_clk = apb_clk / count;
|
||||
|
||||
__raw_writel(CLK_LOW(clk_low) | CLK_HIGH(clk_high),
|
||||
&info->adc_base_spear6xx->clk);
|
||||
__raw_writel(SPEAR_ADC_CLK_LOW(clk_low) | SPEAR_ADC_CLK_HIGH(clk_high),
|
||||
&st->adc_base_spear6xx->clk);
|
||||
}
|
||||
|
||||
static void spear_adc_set_ctrl(struct spear_adc_info *info, int n,
|
||||
static void spear_adc_set_ctrl(struct spear_adc_state *st, int n,
|
||||
u32 val)
|
||||
{
|
||||
__raw_writel(val, &info->adc_base_spear6xx->ch_ctrl[n]);
|
||||
__raw_writel(val, &st->adc_base_spear6xx->ch_ctrl[n]);
|
||||
}
|
||||
|
||||
static u32 spear_adc_get_average(struct spear_adc_info *info)
|
||||
static u32 spear_adc_get_average(struct spear_adc_state *st)
|
||||
{
|
||||
if (of_device_is_compatible(info->np, "st,spear600-adc")) {
|
||||
return __raw_readl(&info->adc_base_spear6xx->average.msb) &
|
||||
DATA_MASK;
|
||||
if (of_device_is_compatible(st->np, "st,spear600-adc")) {
|
||||
return __raw_readl(&st->adc_base_spear6xx->average.msb) &
|
||||
SPEAR_ADC_DATA_MASK;
|
||||
} else {
|
||||
return __raw_readl(&info->adc_base_spear3xx->average) &
|
||||
DATA_MASK;
|
||||
return __raw_readl(&st->adc_base_spear3xx->average) &
|
||||
SPEAR_ADC_DATA_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
static void spear_adc_set_scanrate(struct spear_adc_info *info, u32 rate)
|
||||
static void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate)
|
||||
{
|
||||
if (of_device_is_compatible(info->np, "st,spear600-adc")) {
|
||||
__raw_writel(SCAN_RATE_LO(rate),
|
||||
&info->adc_base_spear6xx->scan_rate_lo);
|
||||
__raw_writel(SCAN_RATE_HI(rate),
|
||||
&info->adc_base_spear6xx->scan_rate_hi);
|
||||
if (of_device_is_compatible(st->np, "st,spear600-adc")) {
|
||||
__raw_writel(SPEAR600_ADC_SCAN_RATE_LO(rate),
|
||||
&st->adc_base_spear6xx->scan_rate_lo);
|
||||
__raw_writel(SPEAR600_ADC_SCAN_RATE_HI(rate),
|
||||
&st->adc_base_spear6xx->scan_rate_hi);
|
||||
} else {
|
||||
__raw_writel(rate, &info->adc_base_spear3xx->scan_rate);
|
||||
__raw_writel(rate, &st->adc_base_spear3xx->scan_rate);
|
||||
}
|
||||
}
|
||||
|
||||
static int spear_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
int *val2,
|
||||
long mask)
|
||||
static int spear_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct spear_adc_info *info = iio_priv(indio_dev);
|
||||
struct spear_adc_state *st = iio_priv(indio_dev);
|
||||
u32 status;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
status = CHANNEL_NUM(chan->channel) |
|
||||
AVG_SAMPLE(info->avg_samples) |
|
||||
START_CONVERSION | ADC_ENABLE;
|
||||
if (info->vref_external == 0)
|
||||
status |= VREF_INTERNAL;
|
||||
status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) |
|
||||
SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) |
|
||||
SPEAR_ADC_STATUS_START_CONVERSION |
|
||||
SPEAR_ADC_STATUS_ADC_ENABLE;
|
||||
if (st->vref_external == 0)
|
||||
status |= SPEAR_ADC_STATUS_VREF_INTERNAL;
|
||||
|
||||
spear_adc_set_status(info, status);
|
||||
wait_for_completion(&info->completion); /* set by ISR */
|
||||
*val = info->value;
|
||||
spear_adc_set_status(st, status);
|
||||
wait_for_completion(&st->completion); /* set by ISR */
|
||||
*val = st->value;
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = info->vref_external;
|
||||
*val2 = DATA_BITS;
|
||||
*val = st->vref_external;
|
||||
*val2 = SPEAR_ADC_DATA_BITS;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = st->current_clk;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int spear_adc_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val,
|
||||
int val2,
|
||||
long mask)
|
||||
{
|
||||
struct spear_adc_state *st = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
|
||||
if (mask != IIO_CHAN_INFO_SAMP_FREQ)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
if ((val < SPEAR_ADC_CLK_MIN) ||
|
||||
(val > SPEAR_ADC_CLK_MAX) ||
|
||||
(val2 != 0)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spear_adc_set_clk(st, val);
|
||||
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define SPEAR_ADC_CHAN(idx) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
|
||||
.channel = idx, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.storagebits = 16, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec spear_adc_iio_channels[] = {
|
||||
|
@ -200,92 +226,34 @@ static const struct iio_chan_spec spear_adc_iio_channels[] = {
|
|||
|
||||
static irqreturn_t spear_adc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct spear_adc_info *info = (struct spear_adc_info *)dev_id;
|
||||
struct spear_adc_state *st = (struct spear_adc_state *)dev_id;
|
||||
|
||||
/* Read value to clear IRQ */
|
||||
info->value = spear_adc_get_average(info);
|
||||
complete(&info->completion);
|
||||
st->value = spear_adc_get_average(st);
|
||||
complete(&st->completion);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int spear_adc_configure(struct spear_adc_info *info)
|
||||
static int spear_adc_configure(struct spear_adc_state *st)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Reset ADC core */
|
||||
spear_adc_set_status(info, 0);
|
||||
__raw_writel(0, &info->adc_base_spear6xx->clk);
|
||||
spear_adc_set_status(st, 0);
|
||||
__raw_writel(0, &st->adc_base_spear6xx->clk);
|
||||
for (i = 0; i < 8; i++)
|
||||
spear_adc_set_ctrl(info, i, 0);
|
||||
spear_adc_set_scanrate(info, 0);
|
||||
spear_adc_set_ctrl(st, i, 0);
|
||||
spear_adc_set_scanrate(st, 0);
|
||||
|
||||
spear_adc_set_clk(info, info->sampling_freq);
|
||||
spear_adc_set_clk(st, st->sampling_freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t spear_adc_read_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct spear_adc_info *info = iio_priv(indio_dev);
|
||||
|
||||
return sprintf(buf, "%d\n", info->current_clk);
|
||||
}
|
||||
|
||||
static ssize_t spear_adc_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 spear_adc_info *info = iio_priv(indio_dev);
|
||||
u32 clk_high, clk_low, count;
|
||||
u32 apb_clk = clk_get_rate(info->clk);
|
||||
unsigned long lval;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &lval);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
if ((lval < CLK_MIN) || (lval > CLK_MAX)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
count = (apb_clk + lval - 1) / lval;
|
||||
clk_low = count / 2;
|
||||
clk_high = count - clk_low;
|
||||
info->current_clk = apb_clk / count;
|
||||
spear_adc_set_clk(info, lval);
|
||||
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
|
||||
spear_adc_read_frequency,
|
||||
spear_adc_write_frequency);
|
||||
|
||||
static struct attribute *spear_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group spear_attribute_group = {
|
||||
.attrs = spear_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info spear_adc_iio_info = {
|
||||
.read_raw = &spear_read_raw,
|
||||
.attrs = &spear_attribute_group,
|
||||
static const struct iio_info spear_adc_info = {
|
||||
.read_raw = &spear_adc_read_raw,
|
||||
.write_raw = &spear_adc_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -293,40 +261,40 @@ static int spear_adc_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct spear_adc_info *info;
|
||||
struct iio_dev *iodev = NULL;
|
||||
struct spear_adc_state *st;
|
||||
struct iio_dev *indio_dev = NULL;
|
||||
int ret = -ENODEV;
|
||||
int irq;
|
||||
|
||||
iodev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_info));
|
||||
if (!iodev) {
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state));
|
||||
if (!indio_dev) {
|
||||
dev_err(dev, "failed allocating iio device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info = iio_priv(iodev);
|
||||
info->np = np;
|
||||
st = iio_priv(indio_dev);
|
||||
st->np = np;
|
||||
|
||||
/*
|
||||
* SPEAr600 has a different register layout than other SPEAr SoC's
|
||||
* (e.g. SPEAr3xx). Let's provide two register base addresses
|
||||
* to support multi-arch kernels.
|
||||
*/
|
||||
info->adc_base_spear6xx = of_iomap(np, 0);
|
||||
if (!info->adc_base_spear6xx) {
|
||||
st->adc_base_spear6xx = of_iomap(np, 0);
|
||||
if (!st->adc_base_spear6xx) {
|
||||
dev_err(dev, "failed mapping memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
info->adc_base_spear3xx =
|
||||
(struct adc_regs_spear3xx __iomem *)info->adc_base_spear6xx;
|
||||
st->adc_base_spear3xx =
|
||||
(struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx;
|
||||
|
||||
info->clk = clk_get(dev, NULL);
|
||||
if (IS_ERR(info->clk)) {
|
||||
st->clk = clk_get(dev, NULL);
|
||||
if (IS_ERR(st->clk)) {
|
||||
dev_err(dev, "failed getting clock\n");
|
||||
goto errout1;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
ret = clk_prepare_enable(st->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed enabling clock\n");
|
||||
goto errout2;
|
||||
|
@ -339,14 +307,15 @@ static int spear_adc_probe(struct platform_device *pdev)
|
|||
goto errout3;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info);
|
||||
ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME,
|
||||
st);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed requesting interrupt\n");
|
||||
goto errout3;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "sampling-frequency",
|
||||
&info->sampling_freq)) {
|
||||
&st->sampling_freq)) {
|
||||
dev_err(dev, "sampling-frequency missing in DT\n");
|
||||
ret = -EINVAL;
|
||||
goto errout3;
|
||||
|
@ -356,28 +325,28 @@ static int spear_adc_probe(struct platform_device *pdev)
|
|||
* Optional avg_samples defaults to 0, resulting in single data
|
||||
* conversion
|
||||
*/
|
||||
of_property_read_u32(np, "average-samples", &info->avg_samples);
|
||||
of_property_read_u32(np, "average-samples", &st->avg_samples);
|
||||
|
||||
/*
|
||||
* Optional vref_external defaults to 0, resulting in internal vref
|
||||
* selection
|
||||
*/
|
||||
of_property_read_u32(np, "vref-external", &info->vref_external);
|
||||
of_property_read_u32(np, "vref-external", &st->vref_external);
|
||||
|
||||
spear_adc_configure(info);
|
||||
spear_adc_configure(st);
|
||||
|
||||
platform_set_drvdata(pdev, iodev);
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
init_completion(&info->completion);
|
||||
init_completion(&st->completion);
|
||||
|
||||
iodev->name = MOD_NAME;
|
||||
iodev->dev.parent = dev;
|
||||
iodev->info = &spear_adc_iio_info;
|
||||
iodev->modes = INDIO_DIRECT_MODE;
|
||||
iodev->channels = spear_adc_iio_channels;
|
||||
iodev->num_channels = ARRAY_SIZE(spear_adc_iio_channels);
|
||||
indio_dev->name = SPEAR_ADC_MOD_NAME;
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->info = &spear_adc_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = spear_adc_iio_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels);
|
||||
|
||||
ret = iio_device_register(iodev);
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto errout3;
|
||||
|
||||
|
@ -386,23 +355,23 @@ static int spear_adc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
errout3:
|
||||
clk_disable_unprepare(info->clk);
|
||||
clk_disable_unprepare(st->clk);
|
||||
errout2:
|
||||
clk_put(info->clk);
|
||||
clk_put(st->clk);
|
||||
errout1:
|
||||
iounmap(info->adc_base_spear6xx);
|
||||
iounmap(st->adc_base_spear6xx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spear_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *iodev = platform_get_drvdata(pdev);
|
||||
struct spear_adc_info *info = iio_priv(iodev);
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct spear_adc_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(iodev);
|
||||
clk_disable_unprepare(info->clk);
|
||||
clk_put(info->clk);
|
||||
iounmap(info->adc_base_spear6xx);
|
||||
iio_device_unregister(indio_dev);
|
||||
clk_disable_unprepare(st->clk);
|
||||
clk_put(st->clk);
|
||||
iounmap(st->adc_base_spear6xx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -419,7 +388,7 @@ static struct platform_driver spear_adc_driver = {
|
|||
.probe = spear_adc_probe,
|
||||
.remove = spear_adc_remove,
|
||||
.driver = {
|
||||
.name = MOD_NAME,
|
||||
.name = SPEAR_ADC_MOD_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(spear_adc_dt_ids),
|
||||
},
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
#define ID_ADT75XX 0x10
|
||||
|
||||
/*
|
||||
* struct adt7316_chip_info - chip specifc information
|
||||
* struct adt7316_chip_info - chip specific information
|
||||
*/
|
||||
|
||||
struct adt7316_chip_info {
|
||||
|
@ -208,7 +208,7 @@ struct adt7316_chip_info {
|
|||
(ADT7316_TEMP_INT_MASK)
|
||||
|
||||
/*
|
||||
* struct adt7316_chip_info - chip specifc information
|
||||
* struct adt7316_chip_info - chip specific information
|
||||
*/
|
||||
|
||||
struct adt7316_limit_regs {
|
||||
|
|
|
@ -78,7 +78,7 @@ enum {
|
|||
};
|
||||
|
||||
/*
|
||||
* struct ad7152_chip_info - chip specifc information
|
||||
* struct ad7152_chip_info - chip specific information
|
||||
*/
|
||||
|
||||
struct ad7152_chip_info {
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
#define AD7746_CAPDAC_DACP(x) ((x) & 0x7F)
|
||||
|
||||
/*
|
||||
* struct ad7746_chip_info - chip specifc information
|
||||
* struct ad7746_chip_info - chip specific information
|
||||
*/
|
||||
|
||||
struct ad7746_chip_info {
|
||||
|
|
|
@ -269,6 +269,10 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable);
|
|||
|
||||
int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable);
|
||||
|
||||
void st_sensors_power_enable(struct iio_dev *indio_dev);
|
||||
|
||||
void st_sensors_power_disable(struct iio_dev *indio_dev);
|
||||
|
||||
int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr);
|
||||
|
||||
int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable);
|
||||
|
|
|
@ -122,6 +122,19 @@ struct iio_channel
|
|||
int iio_read_channel_raw(struct iio_channel *chan,
|
||||
int *val);
|
||||
|
||||
/**
|
||||
* iio_read_channel_average_raw() - read from a given channel
|
||||
* @chan: The channel being queried.
|
||||
* @val: Value read back.
|
||||
*
|
||||
* Note raw reads from iio channels are in adc counts and hence
|
||||
* scale will need to be applied if standard units required.
|
||||
*
|
||||
* In opposit to the normal iio_read_channel_raw this function
|
||||
* returns the average of multiple reads.
|
||||
*/
|
||||
int iio_read_channel_average_raw(struct iio_channel *chan, int *val);
|
||||
|
||||
/**
|
||||
* iio_read_channel_processed() - read processed value from a given channel
|
||||
* @chan: The channel being queried.
|
||||
|
|
Loading…
Reference in New Issue