mirror of https://gitee.com/openkylin/linux.git
Third set of new device support, functionality and cleanups for IIO in the 4.9 cycle.
Given Linus is hinting (strongly!) at an rc8 this last set is hopefully in time for the 4.9 merge window. The zpa2326 and si1145 drivers provide fine illustrations that devices aren't getting any simpler! I'm also particularly pleased Linus Walliej did such a thorough job of cleaning up one of my old drivers. New device support * mCube MC3230 accelerometer - new fairly minimal driver. * Murata zpa2326 - extensive new driver supporting the rather 'novel' buffering of data this device provides and handling both it's own data ready trigger and other triggers rather elegantly. * si1141, si1142, si1143, si1145, si1146 and si1147 proximity, UV, visible and IR sensors. - another extensive new driver supporting all the key bits of what this set of devices supplies including dataready triggers, buffers and all the various data channels. Functionality * kxsd9 - Linus brought this scratch driver I wrote in one afternoon years ago up to date adding lots of good stuff along the way. - SPI support after extensive rework of the driver. - Triggered buffer capture support. - Runtime PM. - Regulator handling. - Mounting matrix support. * mma7660 - Add MODULE_DEVICE_TABLE to support autoprobing. Cleanups * ad5933 - Align some function arguements nicely. * med_z188 - Constify iio_info structure. * sca3000 - Implement IIO_CHAN_INFO_SAMP_FREQ rather than a hand rolled attr. There are still quite a few drivers that would benefit from similar updates. * ssp_sensors - Constify iio_info structures in accel and gyro drivers. -----BEGIN PGP SIGNATURE----- iQIuBAABCAAYBQJX4C9hERxqaWMyM0BrZXJuZWwub3JnAAoJEFSFNJnE9BaIygAP /2NSgQmtVAtRL1XSnZaRgICEuW3cqQPYRUP74hUxKY10bYnxr8Vvx5BWIDWYrfnN 7xrhKCcnnRXIMrpBRN2FRSTFaFyuHMaF5uBszZS5A+xeue99K6+OuDe0ZhcquMWv rLlgQgruwOuIPqUFL//b3r5XRso/Do63hjGFZKAL9JDgbt6DGYN90WmIN0TE7axG KayzNaWpWHO3ugagXC/CW/1bWljfV2dairGcOvTGsBw2hCqdQl1i2JjU0YFWkrKX 8jtIaqgtTurLsldUoBLGQQbZozcXFmgqEse+c/XCL0uhsKJY79GJx2Yy9m8wO0cr DoaSdzBwEyT7p6S79d8X9Ft5XHHcYhuuvlEcwmF4BknAZg+zE/WrINhkq8ynP8Mv dp5mVHxO78Zq+5wLGgfIhaDykWQ+Tk7NtIEmrWr0mzD5llCzTHGdhXqjYu+s7l3f niGtlk514nsqkoTZm/PEmxhut9UWTcq1ORWo9/2cmjX72rq+Xupubs7zFo5QPCyq UsaMDlmRor7XrdkAbEhMwP17YGR4d93vhQ+3BYEDKY7lEakdcNvn16c0Qq5trvIH J9BLwTCJt/nAYNdGoSdd2FsQ9r9FQVdjKmYSfh5aem7IgB9mfKQvkESir/+r160B KUpH9ctJYqzBeB7a7yHqVVkd2RRd1lp57ND1qoLSpqv5 =2Az/ -----END PGP SIGNATURE----- Merge tag 'iio-for-4.9c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Third set of new device support, functionality and cleanups for IIO in the 4.9 cycle. Given Linus is hinting (strongly!) at an rc8 this last set is hopefully in time for the 4.9 merge window. The zpa2326 and si1145 drivers provide fine illustrations that devices aren't getting any simpler! I'm also particularly pleased Linus Walliej did such a thorough job of cleaning up one of my old drivers. New device support * mCube MC3230 accelerometer - new fairly minimal driver. * Murata zpa2326 - extensive new driver supporting the rather 'novel' buffering of data this device provides and handling both it's own data ready trigger and other triggers rather elegantly. * si1141, si1142, si1143, si1145, si1146 and si1147 proximity, UV, visible and IR sensors. - another extensive new driver supporting all the key bits of what this set of devices supplies including dataready triggers, buffers and all the various data channels. Functionality * kxsd9 - Linus brought this scratch driver I wrote in one afternoon years ago up to date adding lots of good stuff along the way. - SPI support after extensive rework of the driver. - Triggered buffer capture support. - Runtime PM. - Regulator handling. - Mounting matrix support. * mma7660 - Add MODULE_DEVICE_TABLE to support autoprobing. Cleanups * ad5933 - Align some function arguements nicely. * med_z188 - Constify iio_info structure. * sca3000 - Implement IIO_CHAN_INFO_SAMP_FREQ rather than a hand rolled attr. There are still quite a few drivers that would benefit from similar updates. * ssp_sensors - Constify iio_info structures in accel and gyro drivers.
This commit is contained in:
commit
888a87b5a9
|
@ -57,6 +57,7 @@ maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
|
|||
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
|
||||
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
|
||||
mc,rv3029c2 Real Time Clock Module with I2C-Bus
|
||||
mcube,mc3230 mCube 3-axis 8-bit digital accelerometer
|
||||
microchip,mcp4531-502 Microchip 7-bit Single I2C Digital Potentiometer (5k)
|
||||
microchip,mcp4531-103 Microchip 7-bit Single I2C Digital Potentiometer (10k)
|
||||
microchip,mcp4531-503 Microchip 7-bit Single I2C Digital Potentiometer (50k)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
Murata ZPA2326 pressure sensor
|
||||
|
||||
Pressure sensor from Murata with SPI and I2C bus interfaces.
|
||||
|
||||
Required properties:
|
||||
- compatible: "murata,zpa2326"
|
||||
- reg: the I2C address or SPI chip select the device will respond to
|
||||
|
||||
Recommended properties for SPI bus usage:
|
||||
- spi-max-frequency: maximum SPI bus frequency as documented in
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Optional properties:
|
||||
- vref-supply: an optional regulator that needs to be on to provide VREF
|
||||
power to the sensor
|
||||
- vdd-supply: an optional regulator that needs to be on to provide VDD
|
||||
power to the sensor
|
||||
- interrupt-parent: phandle to the parent interrupt controller as documented in
|
||||
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
- interrupts: interrupt mapping for IRQ as documented in
|
||||
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
|
||||
Example:
|
||||
|
||||
zpa2326@5c {
|
||||
compatible = "murata,zpa2326";
|
||||
reg = <0x5c>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <12>;
|
||||
vdd-supply = <&ldo_1v8_gnss>;
|
||||
};
|
|
@ -119,14 +119,35 @@ config IIO_ST_ACCEL_SPI_3AXIS
|
|||
|
||||
config KXSD9
|
||||
tristate "Kionix KXSD9 Accelerometer Driver"
|
||||
depends on SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for the Kionix KXSD9 accelerometer.
|
||||
Currently this only supports the device via an SPI interface.
|
||||
It can be accessed using an (optional) SPI or I2C interface.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called kxsd9.
|
||||
|
||||
config KXSD9_SPI
|
||||
tristate "Kionix KXSD9 SPI transport"
|
||||
depends on KXSD9
|
||||
depends on SPI
|
||||
default KXSD9
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say yes here to enable the Kionix KXSD9 accelerometer
|
||||
SPI transport channel.
|
||||
|
||||
config KXSD9_I2C
|
||||
tristate "Kionix KXSD9 I2C transport"
|
||||
depends on KXSD9
|
||||
depends on I2C
|
||||
default KXSD9
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to enable the Kionix KXSD9 accelerometer
|
||||
I2C transport channel.
|
||||
|
||||
config KXCJK1013
|
||||
tristate "Kionix 3-Axis Accelerometer Driver"
|
||||
depends on I2C
|
||||
|
@ -140,6 +161,16 @@ config KXCJK1013
|
|||
To compile this driver as a module, choose M here: the module will
|
||||
be called kxcjk-1013.
|
||||
|
||||
config MC3230
|
||||
tristate "mCube MC3230 Digital Accelerometer Driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for the mCube MC3230 low-g tri-axial
|
||||
digital accelerometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mc3230.
|
||||
|
||||
config MMA7455
|
||||
tristate
|
||||
select IIO_BUFFER
|
||||
|
|
|
@ -13,6 +13,9 @@ obj-$(CONFIG_DMARD09) += dmard09.o
|
|||
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
|
||||
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
|
||||
obj-$(CONFIG_KXSD9) += kxsd9.o
|
||||
obj-$(CONFIG_KXSD9_SPI) += kxsd9-spi.o
|
||||
obj-$(CONFIG_KXSD9_I2C) += kxsd9-i2c.o
|
||||
obj-$(CONFIG_MC3230) += mc3230.o
|
||||
|
||||
obj-$(CONFIG_MMA7455) += mma7455_core.o
|
||||
obj-$(CONFIG_MMA7455_I2C) += mma7455_i2c.o
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "kxsd9.h"
|
||||
|
||||
static int kxsd9_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
static const struct regmap_config config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x0e,
|
||||
};
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, &config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&i2c->dev, "Failed to register i2c regmap %d\n",
|
||||
(int)PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return kxsd9_common_probe(&i2c->dev,
|
||||
regmap,
|
||||
i2c->name);
|
||||
}
|
||||
|
||||
static int kxsd9_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
return kxsd9_common_remove(&client->dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id kxsd9_of_match[] = {
|
||||
{ .compatible = "kionix,kxsd9", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kxsd9_of_match);
|
||||
#else
|
||||
#define kxsd9_of_match NULL
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id kxsd9_i2c_id[] = {
|
||||
{"kxsd9", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id);
|
||||
|
||||
static struct i2c_driver kxsd9_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "kxsd9",
|
||||
.of_match_table = of_match_ptr(kxsd9_of_match),
|
||||
.pm = &kxsd9_dev_pm_ops,
|
||||
},
|
||||
.probe = kxsd9_i2c_probe,
|
||||
.remove = kxsd9_i2c_remove,
|
||||
.id_table = kxsd9_i2c_id,
|
||||
};
|
||||
module_i2c_driver(kxsd9_i2c_driver);
|
|
@ -0,0 +1,56 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "kxsd9.h"
|
||||
|
||||
static int kxsd9_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
static const struct regmap_config config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x0e,
|
||||
};
|
||||
struct regmap *regmap;
|
||||
|
||||
spi->mode = SPI_MODE_0;
|
||||
regmap = devm_regmap_init_spi(spi, &config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n",
|
||||
__func__, PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return kxsd9_common_probe(&spi->dev,
|
||||
regmap,
|
||||
spi_get_device_id(spi)->name);
|
||||
}
|
||||
|
||||
static int kxsd9_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return kxsd9_common_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id kxsd9_spi_id[] = {
|
||||
{"kxsd9", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, kxsd9_spi_id);
|
||||
|
||||
static struct spi_driver kxsd9_spi_driver = {
|
||||
.driver = {
|
||||
.name = "kxsd9",
|
||||
.pm = &kxsd9_dev_pm_ops,
|
||||
},
|
||||
.probe = kxsd9_spi_probe,
|
||||
.remove = kxsd9_spi_remove,
|
||||
.id_table = kxsd9_spi_id,
|
||||
};
|
||||
module_spi_driver(kxsd9_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
|
||||
MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -12,19 +12,25 @@
|
|||
* I have a suitable wire made up.
|
||||
*
|
||||
* TODO: Support the motion detector
|
||||
* Uses register address incrementing so could have a
|
||||
* heavily optimized ring buffer access function.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
|
||||
#include "kxsd9.h"
|
||||
|
||||
#define KXSD9_REG_X 0x00
|
||||
#define KXSD9_REG_Y 0x02
|
||||
|
@ -33,28 +39,45 @@
|
|||
#define KXSD9_REG_RESET 0x0a
|
||||
#define KXSD9_REG_CTRL_C 0x0c
|
||||
|
||||
#define KXSD9_FS_MASK 0x03
|
||||
#define KXSD9_CTRL_C_FS_MASK 0x03
|
||||
#define KXSD9_CTRL_C_FS_8G 0x00
|
||||
#define KXSD9_CTRL_C_FS_6G 0x01
|
||||
#define KXSD9_CTRL_C_FS_4G 0x02
|
||||
#define KXSD9_CTRL_C_FS_2G 0x03
|
||||
#define KXSD9_CTRL_C_MOT_LAT BIT(3)
|
||||
#define KXSD9_CTRL_C_MOT_LEV BIT(4)
|
||||
#define KXSD9_CTRL_C_LP_MASK 0xe0
|
||||
#define KXSD9_CTRL_C_LP_NONE 0x00
|
||||
#define KXSD9_CTRL_C_LP_2000HZC BIT(5)
|
||||
#define KXSD9_CTRL_C_LP_2000HZB BIT(6)
|
||||
#define KXSD9_CTRL_C_LP_2000HZA (BIT(5)|BIT(6))
|
||||
#define KXSD9_CTRL_C_LP_1000HZ BIT(7)
|
||||
#define KXSD9_CTRL_C_LP_500HZ (BIT(7)|BIT(5))
|
||||
#define KXSD9_CTRL_C_LP_100HZ (BIT(7)|BIT(6))
|
||||
#define KXSD9_CTRL_C_LP_50HZ (BIT(7)|BIT(6)|BIT(5))
|
||||
|
||||
#define KXSD9_REG_CTRL_B 0x0d
|
||||
|
||||
#define KXSD9_CTRL_B_CLK_HLD BIT(7)
|
||||
#define KXSD9_CTRL_B_ENABLE BIT(6)
|
||||
#define KXSD9_CTRL_B_ST BIT(5) /* Self-test */
|
||||
|
||||
#define KXSD9_REG_CTRL_A 0x0e
|
||||
|
||||
#define KXSD9_READ(a) (0x80 | (a))
|
||||
#define KXSD9_WRITE(a) (a)
|
||||
|
||||
#define KXSD9_STATE_RX_SIZE 2
|
||||
#define KXSD9_STATE_TX_SIZE 2
|
||||
/**
|
||||
* struct kxsd9_state - device related storage
|
||||
* @buf_lock: protect the rx and tx buffers.
|
||||
* @us: spi device
|
||||
* @rx: single rx buffer storage
|
||||
* @tx: single tx buffer storage
|
||||
**/
|
||||
* @dev: pointer to the parent device
|
||||
* @map: regmap to the device
|
||||
* @orientation: mounting matrix, flipped axis etc
|
||||
* @regs: regulators for this device, VDD and IOVDD
|
||||
* @scale: the current scaling setting
|
||||
*/
|
||||
struct kxsd9_state {
|
||||
struct mutex buf_lock;
|
||||
struct spi_device *us;
|
||||
u8 rx[KXSD9_STATE_RX_SIZE] ____cacheline_aligned;
|
||||
u8 tx[KXSD9_STATE_TX_SIZE];
|
||||
struct device *dev;
|
||||
struct regmap *map;
|
||||
struct iio_mount_matrix orientation;
|
||||
struct regulator_bulk_data regs[2];
|
||||
u8 scale;
|
||||
};
|
||||
|
||||
#define KXSD9_SCALE_2G "0.011978"
|
||||
|
@ -65,6 +88,14 @@ struct kxsd9_state {
|
|||
/* reverse order */
|
||||
static const int kxsd9_micro_scales[4] = { 47853, 35934, 23927, 11978 };
|
||||
|
||||
#define KXSD9_ZERO_G_OFFSET -2048
|
||||
|
||||
/*
|
||||
* Regulator names
|
||||
*/
|
||||
static const char kxsd9_reg_vdd[] = "vdd";
|
||||
static const char kxsd9_reg_iovdd[] = "iovdd";
|
||||
|
||||
static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
|
||||
{
|
||||
int ret, i;
|
||||
|
@ -79,42 +110,17 @@ static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
|
|||
if (!foundit)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&st->buf_lock);
|
||||
ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
|
||||
ret = regmap_update_bits(st->map,
|
||||
KXSD9_REG_CTRL_C,
|
||||
KXSD9_CTRL_C_FS_MASK,
|
||||
i);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C);
|
||||
st->tx[1] = (ret & ~KXSD9_FS_MASK) | i;
|
||||
|
||||
ret = spi_write(st->us, st->tx, 2);
|
||||
/* Cached scale when the sensor is powered down */
|
||||
st->scale = i;
|
||||
|
||||
error_ret:
|
||||
mutex_unlock(&st->buf_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kxsd9_read(struct iio_dev *indio_dev, u8 address)
|
||||
{
|
||||
int ret;
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
struct spi_transfer xfers[] = {
|
||||
{
|
||||
.bits_per_word = 8,
|
||||
.len = 1,
|
||||
.delay_usecs = 200,
|
||||
.tx_buf = st->tx,
|
||||
}, {
|
||||
.bits_per_word = 8,
|
||||
.len = 2,
|
||||
.rx_buf = st->rx,
|
||||
},
|
||||
};
|
||||
|
||||
mutex_lock(&st->buf_lock);
|
||||
st->tx[0] = KXSD9_READ(address);
|
||||
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
|
||||
if (!ret)
|
||||
ret = (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0);
|
||||
mutex_unlock(&st->buf_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -136,6 +142,9 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev,
|
|||
long mask)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
|
||||
pm_runtime_get_sync(st->dev);
|
||||
|
||||
if (mask == IIO_CHAN_INFO_SCALE) {
|
||||
/* Check no integer component */
|
||||
|
@ -144,6 +153,9 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev,
|
|||
ret = kxsd9_write_scale(indio_dev, val2);
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(st->dev);
|
||||
pm_runtime_put_autosuspend(st->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -153,46 +165,154 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
|
|||
{
|
||||
int ret = -EINVAL;
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
unsigned int regval;
|
||||
__be16 raw_val;
|
||||
u16 nval;
|
||||
|
||||
pm_runtime_get_sync(st->dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = kxsd9_read(indio_dev, chan->address);
|
||||
if (ret < 0)
|
||||
ret = regmap_bulk_read(st->map, chan->address, &raw_val,
|
||||
sizeof(raw_val));
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
*val = ret;
|
||||
nval = be16_to_cpu(raw_val);
|
||||
/* Only 12 bits are valid */
|
||||
nval >>= 4;
|
||||
*val = nval;
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
/* This has a bias of -2048 */
|
||||
*val = KXSD9_ZERO_G_OFFSET;
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
|
||||
ret = regmap_read(st->map,
|
||||
KXSD9_REG_CTRL_C,
|
||||
®val);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
*val = 0;
|
||||
*val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK];
|
||||
*val2 = kxsd9_micro_scales[regval & KXSD9_CTRL_C_FS_MASK];
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
break;
|
||||
}
|
||||
|
||||
error_ret:
|
||||
pm_runtime_mark_last_busy(st->dev);
|
||||
pm_runtime_put_autosuspend(st->dev);
|
||||
|
||||
return ret;
|
||||
};
|
||||
#define KXSD9_ACCEL_CHAN(axis) \
|
||||
|
||||
static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
|
||||
{
|
||||
const struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
/* 4 * 16bit values AND timestamp */
|
||||
__be16 hw_values[8];
|
||||
|
||||
ret = regmap_bulk_read(st->map,
|
||||
KXSD9_REG_X,
|
||||
&hw_values,
|
||||
8);
|
||||
if (ret) {
|
||||
dev_err(st->dev,
|
||||
"error reading data\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev,
|
||||
hw_values,
|
||||
iio_get_time_ns(indio_dev));
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int kxsd9_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
|
||||
pm_runtime_get_sync(st->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kxsd9_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
|
||||
pm_runtime_mark_last_busy(st->dev);
|
||||
pm_runtime_put_autosuspend(st->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops kxsd9_buffer_setup_ops = {
|
||||
.preenable = kxsd9_buffer_preenable,
|
||||
.postenable = iio_triggered_buffer_postenable,
|
||||
.predisable = iio_triggered_buffer_predisable,
|
||||
.postdisable = kxsd9_buffer_postdisable,
|
||||
};
|
||||
|
||||
static const struct iio_mount_matrix *
|
||||
kxsd9_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
|
||||
return &st->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info kxsd9_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, kxsd9_get_mount_matrix),
|
||||
{ },
|
||||
};
|
||||
|
||||
#define KXSD9_ACCEL_CHAN(axis, index) \
|
||||
{ \
|
||||
.type = IIO_ACCEL, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET), \
|
||||
.ext_info = kxsd9_ext_info, \
|
||||
.address = KXSD9_REG_##axis, \
|
||||
.scan_index = index, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 12, \
|
||||
.storagebits = 16, \
|
||||
.shift = 4, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec kxsd9_channels[] = {
|
||||
KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
|
||||
KXSD9_ACCEL_CHAN(X, 0),
|
||||
KXSD9_ACCEL_CHAN(Y, 1),
|
||||
KXSD9_ACCEL_CHAN(Z, 2),
|
||||
{
|
||||
.type = IIO_VOLTAGE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.indexed = 1,
|
||||
.address = KXSD9_REG_AUX,
|
||||
}
|
||||
.scan_index = 3,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 12,
|
||||
.storagebits = 16,
|
||||
.shift = 4,
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
};
|
||||
|
||||
static const struct attribute_group kxsd9_attribute_group = {
|
||||
|
@ -203,17 +323,69 @@ static int kxsd9_power_up(struct kxsd9_state *st)
|
|||
{
|
||||
int ret;
|
||||
|
||||
st->tx[0] = 0x0d;
|
||||
st->tx[1] = 0x40;
|
||||
ret = spi_write(st->us, st->tx, 2);
|
||||
/* Enable the regulators */
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(st->regs), st->regs);
|
||||
if (ret) {
|
||||
dev_err(st->dev, "Cannot enable regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Power up */
|
||||
ret = regmap_write(st->map,
|
||||
KXSD9_REG_CTRL_B,
|
||||
KXSD9_CTRL_B_ENABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->tx[0] = 0x0c;
|
||||
st->tx[1] = 0x9b;
|
||||
return spi_write(st->us, st->tx, 2);
|
||||
/*
|
||||
* Set 1000Hz LPF, 2g fullscale, motion wakeup threshold 1g,
|
||||
* latched wakeup
|
||||
*/
|
||||
ret = regmap_write(st->map,
|
||||
KXSD9_REG_CTRL_C,
|
||||
KXSD9_CTRL_C_LP_1000HZ |
|
||||
KXSD9_CTRL_C_MOT_LEV |
|
||||
KXSD9_CTRL_C_MOT_LAT |
|
||||
st->scale);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Power-up time depends on the LPF setting, but typ 15.9 ms, let's
|
||||
* set 20 ms to allow for some slack.
|
||||
*/
|
||||
msleep(20);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int kxsd9_power_down(struct kxsd9_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Set into low power mode - since there may be more users of the
|
||||
* regulators this is the first step of the power saving: it will
|
||||
* make sure we conserve power even if there are others users on the
|
||||
* regulators.
|
||||
*/
|
||||
ret = regmap_update_bits(st->map,
|
||||
KXSD9_REG_CTRL_B,
|
||||
KXSD9_CTRL_B_ENABLE,
|
||||
0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable the regulators */
|
||||
ret = regulator_bulk_disable(ARRAY_SIZE(st->regs), st->regs);
|
||||
if (ret) {
|
||||
dev_err(st->dev, "Cannot disable regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_info kxsd9_info = {
|
||||
.read_raw = &kxsd9_read_raw,
|
||||
.write_raw = &kxsd9_write_raw,
|
||||
|
@ -221,57 +393,136 @@ static const struct iio_info kxsd9_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int kxsd9_probe(struct spi_device *spi)
|
||||
/* Four channels apart from timestamp, scan mask = 0x0f */
|
||||
static const unsigned long kxsd9_scan_masks[] = { 0xf, 0 };
|
||||
|
||||
int kxsd9_common_probe(struct device *dev,
|
||||
struct regmap *map,
|
||||
const char *name)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct kxsd9_state *st;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
st->dev = dev;
|
||||
st->map = map;
|
||||
|
||||
st->us = spi;
|
||||
mutex_init(&st->buf_lock);
|
||||
indio_dev->channels = kxsd9_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(kxsd9_channels);
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->name = name;
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->info = &kxsd9_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->available_scan_masks = kxsd9_scan_masks;
|
||||
|
||||
/* Read the mounting matrix, if present */
|
||||
ret = of_iio_read_mount_matrix(dev,
|
||||
"mount-matrix",
|
||||
&st->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Fetch and turn on regulators */
|
||||
st->regs[0].supply = kxsd9_reg_vdd;
|
||||
st->regs[1].supply = kxsd9_reg_iovdd;
|
||||
ret = devm_regulator_bulk_get(dev,
|
||||
ARRAY_SIZE(st->regs),
|
||||
st->regs);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot get regulators\n");
|
||||
return ret;
|
||||
}
|
||||
/* Default scaling */
|
||||
st->scale = KXSD9_CTRL_C_FS_2G;
|
||||
|
||||
spi->mode = SPI_MODE_0;
|
||||
spi_setup(spi);
|
||||
kxsd9_power_up(st);
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
}
|
||||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
kxsd9_trigger_handler,
|
||||
&kxsd9_buffer_setup_ops);
|
||||
if (ret) {
|
||||
dev_err(dev, "triggered buffer setup failed\n");
|
||||
goto err_power_down;
|
||||
}
|
||||
|
||||
static int kxsd9_remove(struct spi_device *spi)
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto err_cleanup_buffer;
|
||||
|
||||
dev_set_drvdata(dev, indio_dev);
|
||||
|
||||
/* Enable runtime PM */
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
/*
|
||||
* Set autosuspend to two orders of magnitude larger than the
|
||||
* start-up time. 20ms start-up time means 2000ms autosuspend,
|
||||
* i.e. 2 seconds.
|
||||
*/
|
||||
pm_runtime_set_autosuspend_delay(dev, 2000);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_cleanup_buffer:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_power_down:
|
||||
kxsd9_power_down(st);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(kxsd9_common_probe);
|
||||
|
||||
int kxsd9_common_remove(struct device *dev)
|
||||
{
|
||||
iio_device_unregister(spi_get_drvdata(spi));
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
iio_device_unregister(indio_dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
pm_runtime_disable(dev);
|
||||
kxsd9_power_down(st);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(kxsd9_common_remove);
|
||||
|
||||
static const struct spi_device_id kxsd9_id[] = {
|
||||
{"kxsd9", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, kxsd9_id);
|
||||
#ifdef CONFIG_PM
|
||||
static int kxsd9_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
|
||||
static struct spi_driver kxsd9_driver = {
|
||||
.driver = {
|
||||
.name = "kxsd9",
|
||||
},
|
||||
.probe = kxsd9_probe,
|
||||
.remove = kxsd9_remove,
|
||||
.id_table = kxsd9_id,
|
||||
return kxsd9_power_down(st);
|
||||
}
|
||||
|
||||
static int kxsd9_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct kxsd9_state *st = iio_priv(indio_dev);
|
||||
|
||||
return kxsd9_power_up(st);
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
const struct dev_pm_ops kxsd9_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(kxsd9_runtime_suspend,
|
||||
kxsd9_runtime_resume, NULL)
|
||||
};
|
||||
module_spi_driver(kxsd9_driver);
|
||||
EXPORT_SYMBOL(kxsd9_dev_pm_ops);
|
||||
|
||||
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
|
||||
MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
|
||||
MODULE_DESCRIPTION("Kionix KXSD9 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define KXSD9_STATE_RX_SIZE 2
|
||||
#define KXSD9_STATE_TX_SIZE 2
|
||||
|
||||
int kxsd9_common_probe(struct device *dev,
|
||||
struct regmap *map,
|
||||
const char *name);
|
||||
int kxsd9_common_remove(struct device *dev);
|
||||
|
||||
extern const struct dev_pm_ops kxsd9_dev_pm_ops;
|
|
@ -0,0 +1,211 @@
|
|||
/**
|
||||
* mCube MC3230 3-Axis Accelerometer
|
||||
*
|
||||
* Copyright (c) 2016 Hans de Goede <hdegoede@redhat.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.
|
||||
*
|
||||
* IIO driver for mCube MC3230; 7-bit I2C address: 0x4c.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#define MC3230_REG_XOUT 0x00
|
||||
#define MC3230_REG_YOUT 0x01
|
||||
#define MC3230_REG_ZOUT 0x02
|
||||
|
||||
#define MC3230_REG_MODE 0x07
|
||||
#define MC3230_MODE_OPCON_MASK 0x03
|
||||
#define MC3230_MODE_OPCON_WAKE 0x01
|
||||
#define MC3230_MODE_OPCON_STANDBY 0x03
|
||||
|
||||
#define MC3230_REG_CHIP_ID 0x18
|
||||
#define MC3230_CHIP_ID 0x01
|
||||
|
||||
#define MC3230_REG_PRODUCT_CODE 0x3b
|
||||
#define MC3230_PRODUCT_CODE 0x19
|
||||
|
||||
/*
|
||||
* The accelerometer has one measurement range:
|
||||
*
|
||||
* -1.5g - +1.5g (8-bit, signed)
|
||||
*
|
||||
* scale = (1.5 + 1.5) * 9.81 / (2^8 - 1) = 0.115411765
|
||||
*/
|
||||
|
||||
static const int mc3230_nscale = 115411765;
|
||||
|
||||
#define MC3230_CHANNEL(reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = reg, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mc3230_channels[] = {
|
||||
MC3230_CHANNEL(MC3230_REG_XOUT, X),
|
||||
MC3230_CHANNEL(MC3230_REG_YOUT, Y),
|
||||
MC3230_CHANNEL(MC3230_REG_ZOUT, Z),
|
||||
};
|
||||
|
||||
struct mc3230_data {
|
||||
struct i2c_client *client;
|
||||
};
|
||||
|
||||
static int mc3230_set_opcon(struct mc3230_data *data, int opcon)
|
||||
{
|
||||
int ret;
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, MC3230_REG_MODE);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to read mode reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret &= ~MC3230_MODE_OPCON_MASK;
|
||||
ret |= opcon;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, MC3230_REG_MODE, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to write mode reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mc3230_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct mc3230_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = i2c_smbus_read_byte_data(data->client, chan->address);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = sign_extend32(ret, 7);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = mc3230_nscale;
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info mc3230_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = mc3230_read_raw,
|
||||
};
|
||||
|
||||
static int mc3230_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct iio_dev *indio_dev;
|
||||
struct mc3230_data *data;
|
||||
|
||||
/* First check chip-id and product-id */
|
||||
ret = i2c_smbus_read_byte_data(client, MC3230_REG_CHIP_ID);
|
||||
if (ret != MC3230_CHIP_ID)
|
||||
return (ret < 0) ? ret : -ENODEV;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, MC3230_REG_PRODUCT_CODE);
|
||||
if (ret != MC3230_PRODUCT_CODE)
|
||||
return (ret < 0) ? ret : -ENODEV;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev) {
|
||||
dev_err(&client->dev, "iio allocation failed!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &mc3230_info;
|
||||
indio_dev->name = "mc3230";
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = mc3230_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mc3230_channels);
|
||||
|
||||
ret = mc3230_set_opcon(data, MC3230_MODE_OPCON_WAKE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "device_register failed\n");
|
||||
mc3230_set_opcon(data, MC3230_MODE_OPCON_STANDBY);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mc3230_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
return mc3230_set_opcon(iio_priv(indio_dev), MC3230_MODE_OPCON_STANDBY);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mc3230_suspend(struct device *dev)
|
||||
{
|
||||
struct mc3230_data *data;
|
||||
|
||||
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
|
||||
|
||||
return mc3230_set_opcon(data, MC3230_MODE_OPCON_STANDBY);
|
||||
}
|
||||
|
||||
static int mc3230_resume(struct device *dev)
|
||||
{
|
||||
struct mc3230_data *data;
|
||||
|
||||
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
|
||||
|
||||
return mc3230_set_opcon(data, MC3230_MODE_OPCON_WAKE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume);
|
||||
|
||||
static const struct i2c_device_id mc3230_i2c_id[] = {
|
||||
{"mc3230", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id);
|
||||
|
||||
static struct i2c_driver mc3230_driver = {
|
||||
.driver = {
|
||||
.name = "mc3230",
|
||||
.pm = &mc3230_pm_ops,
|
||||
},
|
||||
.probe = mc3230_probe,
|
||||
.remove = mc3230_remove,
|
||||
.id_table = mc3230_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(mc3230_driver);
|
||||
|
||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
||||
MODULE_DESCRIPTION("mCube MC3230 3-Axis Accelerometer driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -251,6 +251,7 @@ static const struct i2c_device_id mma7660_i2c_id[] = {
|
|||
{"mma7660", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id);
|
||||
|
||||
static const struct acpi_device_id mma7660_acpi_id[] = {
|
||||
{"MMA7660", 0},
|
||||
|
|
|
@ -74,7 +74,7 @@ static int ssp_accel_write_raw(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct iio_info ssp_accel_iio_info = {
|
||||
static const struct iio_info ssp_accel_iio_info = {
|
||||
.read_raw = &ssp_accel_read_raw,
|
||||
.write_raw = &ssp_accel_write_raw,
|
||||
};
|
||||
|
|
|
@ -78,7 +78,7 @@ static int z188_iio_read_raw(struct iio_dev *iio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct iio_info z188_adc_info = {
|
||||
static const struct iio_info z188_adc_info = {
|
||||
.read_raw = &z188_iio_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -74,7 +74,7 @@ static int ssp_gyro_write_raw(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct iio_info ssp_gyro_iio_info = {
|
||||
static const struct iio_info ssp_gyro_iio_info = {
|
||||
.read_raw = &ssp_gyro_read_raw,
|
||||
.write_raw = &ssp_gyro_write_raw,
|
||||
};
|
||||
|
|
|
@ -267,6 +267,19 @@ config PA12203001
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called pa12203001.
|
||||
|
||||
config SI1145
|
||||
tristate "SI1132 and SI1141/2/3/5/6/7 combined ALS, UV index and proximity sensor"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here if you want to build a driver for the Silicon Labs SI1132 or
|
||||
SI1141/2/3/5/6/7 combined ambient light, UV index and proximity sensor
|
||||
chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called si1145.
|
||||
|
||||
config STK3310
|
||||
tristate "STK3310 ALS and proximity sensor"
|
||||
depends on I2C
|
||||
|
|
|
@ -26,6 +26,7 @@ obj-$(CONFIG_OPT3001) += opt3001.o
|
|||
obj-$(CONFIG_PA12203001) += pa12203001.o
|
||||
obj-$(CONFIG_RPR0521) += rpr0521.o
|
||||
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
|
||||
obj-$(CONFIG_SI1145) += si1145.o
|
||||
obj-$(CONFIG_STK3310) += stk3310.o
|
||||
obj-$(CONFIG_TCS3414) += tcs3414.o
|
||||
obj-$(CONFIG_TCS3472) += tcs3472.o
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -187,4 +187,26 @@ config HP206C
|
|||
This driver can also be built as a module. If so, the module will
|
||||
be called hp206c.
|
||||
|
||||
config ZPA2326
|
||||
tristate "Murata ZPA2326 pressure sensor driver"
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select REGMAP
|
||||
select ZPA2326_I2C if I2C
|
||||
select ZPA2326_SPI if SPI_MASTER
|
||||
help
|
||||
Say Y here to build support for the Murata ZPA2326 pressure and
|
||||
temperature sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called zpa2326.
|
||||
|
||||
config ZPA2326_I2C
|
||||
tristate
|
||||
select REGMAP_I2C
|
||||
|
||||
config ZPA2326_SPI
|
||||
tristate
|
||||
select REGMAP_SPI
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -22,6 +22,9 @@ st_pressure-y := st_pressure_core.o
|
|||
st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
|
||||
obj-$(CONFIG_T5403) += t5403.o
|
||||
obj-$(CONFIG_HP206C) += hp206c.o
|
||||
obj-$(CONFIG_ZPA2326) += zpa2326.o
|
||||
obj-$(CONFIG_ZPA2326_I2C) += zpa2326_i2c.o
|
||||
obj-$(CONFIG_ZPA2326_SPI) += zpa2326_spi.o
|
||||
|
||||
obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o
|
||||
obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Murata ZPA2326 pressure and temperature sensor IIO driver
|
||||
*
|
||||
* Copyright (c) 2016 Parrot S.A.
|
||||
*
|
||||
* Author: Gregor Boirie <gregor.boirie@parrot.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef _ZPA2326_H
|
||||
#define _ZPA2326_H
|
||||
|
||||
/* Register map. */
|
||||
#define ZPA2326_REF_P_XL_REG (0x8)
|
||||
#define ZPA2326_REF_P_L_REG (0x9)
|
||||
#define ZPA2326_REF_P_H_REG (0xa)
|
||||
#define ZPA2326_DEVICE_ID_REG (0xf)
|
||||
#define ZPA2326_DEVICE_ID (0xb9)
|
||||
#define ZPA2326_RES_CONF_REG (0x10)
|
||||
#define ZPA2326_CTRL_REG0_REG (0x20)
|
||||
#define ZPA2326_CTRL_REG0_ONE_SHOT BIT(0)
|
||||
#define ZPA2326_CTRL_REG0_ENABLE BIT(1)
|
||||
#define ZPA2326_CTRL_REG1_REG (0x21)
|
||||
#define ZPA2326_CTRL_REG1_MASK_DATA_READY BIT(2)
|
||||
#define ZPA2326_CTRL_REG2_REG (0x22)
|
||||
#define ZPA2326_CTRL_REG2_SWRESET BIT(2)
|
||||
#define ZPA2326_CTRL_REG3_REG (0x23)
|
||||
#define ZPA2326_CTRL_REG3_ODR_SHIFT (4)
|
||||
#define ZPA2326_CTRL_REG3_ENABLE_MEAS BIT(7)
|
||||
#define ZPA2326_INT_SOURCE_REG (0x24)
|
||||
#define ZPA2326_INT_SOURCE_DATA_READY BIT(2)
|
||||
#define ZPA2326_THS_P_LOW_REG (0x25)
|
||||
#define ZPA2326_THS_P_HIGH_REG (0x26)
|
||||
#define ZPA2326_STATUS_REG (0x27)
|
||||
#define ZPA2326_STATUS_P_DA BIT(1)
|
||||
#define ZPA2326_STATUS_FIFO_E BIT(2)
|
||||
#define ZPA2326_STATUS_P_OR BIT(5)
|
||||
#define ZPA2326_PRESS_OUT_XL_REG (0x28)
|
||||
#define ZPA2326_PRESS_OUT_L_REG (0x29)
|
||||
#define ZPA2326_PRESS_OUT_H_REG (0x2a)
|
||||
#define ZPA2326_TEMP_OUT_L_REG (0x2b)
|
||||
#define ZPA2326_TEMP_OUT_H_REG (0x2c)
|
||||
|
||||
struct device;
|
||||
struct regmap;
|
||||
|
||||
bool zpa2326_isreg_writeable(struct device *dev, unsigned int reg);
|
||||
bool zpa2326_isreg_readable(struct device *dev, unsigned int reg);
|
||||
bool zpa2326_isreg_precious(struct device *dev, unsigned int reg);
|
||||
|
||||
/**
|
||||
* zpa2326_probe() - Instantiate and register core ZPA2326 IIO device
|
||||
* @parent: Hardware sampling device the created IIO device will be a child of.
|
||||
* @name: Arbitrary name to identify the device.
|
||||
* @irq: Interrupt line, negative if none.
|
||||
* @hwid: Expected device hardware id.
|
||||
* @regmap: Registers map used to abstract underlying bus accesses.
|
||||
*
|
||||
* Return: Zero when successful, a negative error code otherwise.
|
||||
*/
|
||||
int zpa2326_probe(struct device *parent,
|
||||
const char *name,
|
||||
int irq,
|
||||
unsigned int hwid,
|
||||
struct regmap *regmap);
|
||||
|
||||
/**
|
||||
* zpa2326_remove() - Unregister and destroy core ZPA2326 IIO device.
|
||||
* @parent: Hardware sampling device the IIO device to remove is a child of.
|
||||
*/
|
||||
void zpa2326_remove(const struct device *parent);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#include <linux/pm.h>
|
||||
extern const struct dev_pm_ops zpa2326_pm_ops;
|
||||
#define ZPA2326_PM_OPS (&zpa2326_pm_ops)
|
||||
#else
|
||||
#define ZPA2326_PM_OPS (NULL)
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Murata ZPA2326 I2C pressure and temperature sensor driver
|
||||
*
|
||||
* Copyright (c) 2016 Parrot S.A.
|
||||
*
|
||||
* Author: Gregor Boirie <gregor.boirie@parrot.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "zpa2326.h"
|
||||
|
||||
/*
|
||||
* read_flag_mask:
|
||||
* - address bit 7 must be set to request a register read operation
|
||||
*/
|
||||
static const struct regmap_config zpa2326_regmap_i2c_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.writeable_reg = zpa2326_isreg_writeable,
|
||||
.readable_reg = zpa2326_isreg_readable,
|
||||
.precious_reg = zpa2326_isreg_precious,
|
||||
.max_register = ZPA2326_TEMP_OUT_H_REG,
|
||||
.read_flag_mask = BIT(7),
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
static unsigned int zpa2326_i2c_hwid(const struct i2c_client *client)
|
||||
{
|
||||
#define ZPA2326_SA0(_addr) (_addr & BIT(0))
|
||||
#define ZPA2326_DEVICE_ID_SA0_SHIFT (1)
|
||||
|
||||
/* Identification register bit 1 mirrors device address bit 0. */
|
||||
return (ZPA2326_DEVICE_ID |
|
||||
(ZPA2326_SA0(client->addr) << ZPA2326_DEVICE_ID_SA0_SHIFT));
|
||||
}
|
||||
|
||||
static int zpa2326_probe_i2c(struct i2c_client *client,
|
||||
const struct i2c_device_id *i2c_id)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &zpa2326_regmap_i2c_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "failed to init registers map");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return zpa2326_probe(&client->dev, i2c_id->name, client->irq,
|
||||
zpa2326_i2c_hwid(client), regmap);
|
||||
}
|
||||
|
||||
static int zpa2326_remove_i2c(struct i2c_client *client)
|
||||
{
|
||||
zpa2326_remove(&client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id zpa2326_i2c_ids[] = {
|
||||
{ "zpa2326", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, zpa2326_i2c_ids);
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id zpa2326_i2c_matches[] = {
|
||||
{ .compatible = "murata,zpa2326" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zpa2326_i2c_matches);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver zpa2326_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "zpa2326-i2c",
|
||||
.of_match_table = of_match_ptr(zpa2326_i2c_matches),
|
||||
.pm = ZPA2326_PM_OPS,
|
||||
},
|
||||
.probe = zpa2326_probe_i2c,
|
||||
.remove = zpa2326_remove_i2c,
|
||||
.id_table = zpa2326_i2c_ids,
|
||||
};
|
||||
module_i2c_driver(zpa2326_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Gregor Boirie <gregor.boirie@parrot.com>");
|
||||
MODULE_DESCRIPTION("I2C driver for Murata ZPA2326 pressure sensor");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Murata ZPA2326 SPI pressure and temperature sensor driver
|
||||
*
|
||||
* Copyright (c) 2016 Parrot S.A.
|
||||
*
|
||||
* Author: Gregor Boirie <gregor.boirie@parrot.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "zpa2326.h"
|
||||
|
||||
/*
|
||||
* read_flag_mask:
|
||||
* - address bit 7 must be set to request a register read operation
|
||||
* - address bit 6 must be set to request register address auto increment
|
||||
*/
|
||||
static const struct regmap_config zpa2326_regmap_spi_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.writeable_reg = zpa2326_isreg_writeable,
|
||||
.readable_reg = zpa2326_isreg_readable,
|
||||
.precious_reg = zpa2326_isreg_precious,
|
||||
.max_register = ZPA2326_TEMP_OUT_H_REG,
|
||||
.read_flag_mask = BIT(7) | BIT(6),
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
static int zpa2326_probe_spi(struct spi_device *spi)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
int err;
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &zpa2326_regmap_spi_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&spi->dev, "failed to init registers map");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enforce SPI slave settings to prevent from DT misconfiguration.
|
||||
*
|
||||
* Clock is idle high. Sampling happens on trailing edge, i.e., rising
|
||||
* edge. Maximum bus frequency is 1 MHz. Registers are 8 bits wide.
|
||||
*/
|
||||
spi->mode = SPI_MODE_3;
|
||||
spi->max_speed_hz = min(spi->max_speed_hz, 1000000U);
|
||||
spi->bits_per_word = 8;
|
||||
err = spi_setup(spi);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return zpa2326_probe(&spi->dev, spi_get_device_id(spi)->name,
|
||||
spi->irq, ZPA2326_DEVICE_ID, regmap);
|
||||
}
|
||||
|
||||
static int zpa2326_remove_spi(struct spi_device *spi)
|
||||
{
|
||||
zpa2326_remove(&spi->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id zpa2326_spi_ids[] = {
|
||||
{ "zpa2326", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, zpa2326_spi_ids);
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id zpa2326_spi_matches[] = {
|
||||
{ .compatible = "murata,zpa2326" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zpa2326_spi_matches);
|
||||
#endif
|
||||
|
||||
static struct spi_driver zpa2326_spi_driver = {
|
||||
.driver = {
|
||||
.name = "zpa2326-spi",
|
||||
.of_match_table = of_match_ptr(zpa2326_spi_matches),
|
||||
.pm = ZPA2326_PM_OPS,
|
||||
},
|
||||
.probe = zpa2326_probe_spi,
|
||||
.remove = zpa2326_remove_spi,
|
||||
.id_table = zpa2326_spi_ids,
|
||||
};
|
||||
module_spi_driver(zpa2326_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Gregor Boirie <gregor.boirie@parrot.com>");
|
||||
MODULE_DESCRIPTION("SPI driver for Murata ZPA2326 pressure sensor");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -113,6 +113,7 @@
|
|||
#define SCA3000_OUT_CTRL_BUF_X_EN 0x10
|
||||
#define SCA3000_OUT_CTRL_BUF_Y_EN 0x08
|
||||
#define SCA3000_OUT_CTRL_BUF_Z_EN 0x04
|
||||
#define SCA3000_OUT_CTRL_BUF_DIV_MASK 0x03
|
||||
#define SCA3000_OUT_CTRL_BUF_DIV_4 0x02
|
||||
#define SCA3000_OUT_CTRL_BUF_DIV_2 0x01
|
||||
|
||||
|
|
|
@ -402,6 +402,7 @@ static const struct iio_event_spec sca3000_event = {
|
|||
.channel2 = mod, \
|
||||
.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),\
|
||||
.address = index, \
|
||||
.scan_index = index, \
|
||||
.scan_type = { \
|
||||
|
@ -443,6 +444,97 @@ static u8 sca3000_addresses[3][3] = {
|
|||
SCA3000_MD_CTRL_OR_Z},
|
||||
};
|
||||
|
||||
/**
|
||||
* __sca3000_get_base_freq() obtain mode specific base frequency
|
||||
*
|
||||
* lock must be held
|
||||
**/
|
||||
static inline int __sca3000_get_base_freq(struct sca3000_state *st,
|
||||
const struct sca3000_chip_info *info,
|
||||
int *base_freq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
switch (0x03 & st->rx[0]) {
|
||||
case SCA3000_MEAS_MODE_NORMAL:
|
||||
*base_freq = info->measurement_mode_freq;
|
||||
break;
|
||||
case SCA3000_MEAS_MODE_OP_1:
|
||||
*base_freq = info->option_mode_1_freq;
|
||||
break;
|
||||
case SCA3000_MEAS_MODE_OP_2:
|
||||
*base_freq = info->option_mode_2_freq;
|
||||
break;
|
||||
}
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_raw handler for IIO_CHAN_INFO_SAMP_FREQ
|
||||
*
|
||||
* lock must be held
|
||||
**/
|
||||
static int read_raw_samp_freq(struct sca3000_state *st, int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __sca3000_get_base_freq(st, st->info, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (*val > 0) {
|
||||
ret &= SCA3000_OUT_CTRL_BUF_DIV_MASK;
|
||||
switch (ret) {
|
||||
case SCA3000_OUT_CTRL_BUF_DIV_2:
|
||||
*val /= 2;
|
||||
break;
|
||||
case SCA3000_OUT_CTRL_BUF_DIV_4:
|
||||
*val /= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_raw handler for IIO_CHAN_INFO_SAMP_FREQ
|
||||
*
|
||||
* lock must be held
|
||||
**/
|
||||
static int write_raw_samp_freq(struct sca3000_state *st, int val)
|
||||
{
|
||||
int ret, base_freq, ctrlval;
|
||||
|
||||
ret = __sca3000_get_base_freq(st, st->info, &base_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ctrlval = ret & ~SCA3000_OUT_CTRL_BUF_DIV_MASK;
|
||||
|
||||
if (val == base_freq / 2)
|
||||
ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_2;
|
||||
if (val == base_freq / 4)
|
||||
ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_4;
|
||||
else if (val != base_freq)
|
||||
return -EINVAL;
|
||||
|
||||
return sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL,
|
||||
ctrlval);
|
||||
}
|
||||
|
||||
static int sca3000_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
|
@ -495,11 +587,38 @@ static int sca3000_read_raw(struct iio_dev *indio_dev,
|
|||
*val = -214;
|
||||
*val2 = 600000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
mutex_lock(&st->lock);
|
||||
ret = read_raw_samp_freq(st, val);
|
||||
mutex_unlock(&st->lock);
|
||||
return ret ? ret : IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int sca3000_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct sca3000_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (val2)
|
||||
return -EINVAL;
|
||||
mutex_lock(&st->lock);
|
||||
ret = write_raw_samp_freq(st, val);
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sca3000_read_av_freq() sysfs function to get available frequencies
|
||||
*
|
||||
|
@ -548,133 +667,12 @@ static ssize_t sca3000_read_av_freq(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* __sca3000_get_base_freq() obtain mode specific base frequency
|
||||
*
|
||||
* lock must be held
|
||||
**/
|
||||
static inline int __sca3000_get_base_freq(struct sca3000_state *st,
|
||||
const struct sca3000_chip_info *info,
|
||||
int *base_freq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
switch (0x03 & st->rx[0]) {
|
||||
case SCA3000_MEAS_MODE_NORMAL:
|
||||
*base_freq = info->measurement_mode_freq;
|
||||
break;
|
||||
case SCA3000_MEAS_MODE_OP_1:
|
||||
*base_freq = info->option_mode_1_freq;
|
||||
break;
|
||||
case SCA3000_MEAS_MODE_OP_2:
|
||||
*base_freq = info->option_mode_2_freq;
|
||||
break;
|
||||
}
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sca3000_read_frequency() sysfs interface to get the current frequency
|
||||
**/
|
||||
static ssize_t sca3000_read_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct sca3000_state *st = iio_priv(indio_dev);
|
||||
int ret, len = 0, base_freq = 0, val;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
ret = __sca3000_get_base_freq(st, st->info, &base_freq);
|
||||
if (ret)
|
||||
goto error_ret_mut;
|
||||
ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL);
|
||||
mutex_unlock(&st->lock);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
val = ret;
|
||||
if (base_freq > 0)
|
||||
switch (val & 0x03) {
|
||||
case 0x00:
|
||||
case 0x03:
|
||||
len = sprintf(buf, "%d\n", base_freq);
|
||||
break;
|
||||
case 0x01:
|
||||
len = sprintf(buf, "%d\n", base_freq / 2);
|
||||
break;
|
||||
case 0x02:
|
||||
len = sprintf(buf, "%d\n", base_freq / 4);
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
error_ret_mut:
|
||||
mutex_unlock(&st->lock);
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sca3000_set_frequency() sysfs interface to set the current frequency
|
||||
**/
|
||||
static ssize_t sca3000_set_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 sca3000_state *st = iio_priv(indio_dev);
|
||||
int ret, base_freq = 0;
|
||||
int ctrlval;
|
||||
int val;
|
||||
|
||||
ret = kstrtoint(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
/* What mode are we in? */
|
||||
ret = __sca3000_get_base_freq(st, st->info, &base_freq);
|
||||
if (ret)
|
||||
goto error_free_lock;
|
||||
|
||||
ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL);
|
||||
if (ret < 0)
|
||||
goto error_free_lock;
|
||||
ctrlval = ret;
|
||||
/* clear the bits */
|
||||
ctrlval &= ~0x03;
|
||||
|
||||
if (val == base_freq / 2) {
|
||||
ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_2;
|
||||
} else if (val == base_freq / 4) {
|
||||
ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_4;
|
||||
} else if (val != base_freq) {
|
||||
ret = -EINVAL;
|
||||
goto error_free_lock;
|
||||
}
|
||||
ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL,
|
||||
ctrlval);
|
||||
error_free_lock:
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should only really be registered if ring buffer support is compiled in.
|
||||
* Does no harm however and doing it right would add a fair bit of complexity
|
||||
*/
|
||||
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq);
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
|
||||
sca3000_read_frequency,
|
||||
sca3000_set_frequency);
|
||||
|
||||
/**
|
||||
* sca3000_read_thresh() - query of a threshold
|
||||
**/
|
||||
|
@ -751,7 +749,6 @@ static struct attribute *sca3000_attributes[] = {
|
|||
&iio_dev_attr_measurement_mode_available.dev_attr.attr,
|
||||
&iio_dev_attr_measurement_mode.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -1086,6 +1083,7 @@ static int sca3000_clean_setup(struct sca3000_state *st)
|
|||
static const struct iio_info sca3000_info = {
|
||||
.attrs = &sca3000_attribute_group,
|
||||
.read_raw = &sca3000_read_raw,
|
||||
.write_raw = &sca3000_write_raw,
|
||||
.event_attrs = &sca3000_event_attribute_group,
|
||||
.read_event_value = &sca3000_read_thresh,
|
||||
.write_event_value = &sca3000_write_thresh,
|
||||
|
|
|
@ -156,8 +156,7 @@ static const struct iio_chan_spec ad5933_channels[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int ad5933_i2c_write(struct i2c_client *client,
|
||||
u8 reg, u8 len, u8 *data)
|
||||
static int ad5933_i2c_write(struct i2c_client *client, u8 reg, u8 len, u8 *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -171,8 +170,7 @@ static int ad5933_i2c_write(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ad5933_i2c_read(struct i2c_client *client,
|
||||
u8 reg, u8 len, u8 *data)
|
||||
static int ad5933_i2c_read(struct i2c_client *client, u8 reg, u8 len, u8 *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -269,7 +267,8 @@ static int ad5933_setup(struct ad5933_state *st)
|
|||
dat = cpu_to_be16(st->settling_cycles);
|
||||
|
||||
ret = ad5933_i2c_write(st->client,
|
||||
AD5933_REG_SETTLING_CYCLES, 2, (u8 *)&dat);
|
||||
AD5933_REG_SETTLING_CYCLES,
|
||||
2, (u8 *)&dat);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -294,8 +293,8 @@ static void ad5933_calc_out_ranges(struct ad5933_state *st)
|
|||
*/
|
||||
|
||||
static ssize_t ad5933_show_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad5933_state *st = iio_priv(indio_dev);
|
||||
|
@ -322,9 +321,9 @@ static ssize_t ad5933_show_frequency(struct device *dev,
|
|||
}
|
||||
|
||||
static ssize_t ad5933_store_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad5933_state *st = iio_priv(indio_dev);
|
||||
|
@ -357,8 +356,8 @@ static IIO_DEVICE_ATTR(out_voltage0_freq_increment, S_IRUGO | S_IWUSR,
|
|||
AD5933_REG_FREQ_INC);
|
||||
|
||||
static ssize_t ad5933_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad5933_state *st = iio_priv(indio_dev);
|
||||
|
@ -399,9 +398,9 @@ static ssize_t ad5933_show(struct device *dev,
|
|||
}
|
||||
|
||||
static ssize_t ad5933_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad5933_state *st = iio_priv(indio_dev);
|
||||
|
@ -451,7 +450,8 @@ static ssize_t ad5933_store(struct device *dev,
|
|||
|
||||
dat = cpu_to_be16(val);
|
||||
ret = ad5933_i2c_write(st->client,
|
||||
AD5933_REG_SETTLING_CYCLES, 2, (u8 *)&dat);
|
||||
AD5933_REG_SETTLING_CYCLES,
|
||||
2, (u8 *)&dat);
|
||||
break;
|
||||
case AD5933_FREQ_POINTS:
|
||||
val = clamp(val, (u16)0, (u16)511);
|
||||
|
@ -545,8 +545,8 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
|
|||
goto out;
|
||||
|
||||
ret = ad5933_i2c_read(st->client,
|
||||
AD5933_REG_TEMP_DATA, 2,
|
||||
(u8 *)&dat);
|
||||
AD5933_REG_TEMP_DATA,
|
||||
2, (u8 *)&dat);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
@ -705,7 +705,7 @@ static void ad5933_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
static int ad5933_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int ret, voltage_uv = 0;
|
||||
struct ad5933_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
|
|
Loading…
Reference in New Issue