FXAS21002C is a 3 axis gyroscope with integrated temperature sensor
Signed-off-by: Afonso Bordado <[email protected]>
---
Changes in v4
- Remove CONFIG_OF ifdefs
- Remove the use of the of_match_ptr macro
- Split bindings into a separate patch
- Remove interrupt-parent from binding documentation
- Whitespace fixes
- Remove scale and sample frequency tables
- Place MAINTAINERS block in correct position
Changes in v3
- Use unsigned int on regmap functions
- Remove the export of the regmap config
- Fix undefined behaviour on dev_err call
- Minor cleanups
Changes in v2
- Use ANSI C Comments
- Minor cleanups
- More dscriptive devicetree bindings
drivers/iio/gyro/Kconfig | 11 +
drivers/iio/gyro/Makefile | 1 +
drivers/iio/gyro/fxas21002c.c | 378 ++++++++++++++++++++++++++++++++++
3 files changed, 390 insertions(+)
create mode 100644 drivers/iio/gyro/fxas21002c.c
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index 3126cf05e6b9..d71e33ea9fa4 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -73,6 +73,17 @@ config BMG160_SPI
tristate
select REGMAP_SPI
+config FXAS21002C
+ tristate "Freescale FXAS21002C Gyroscope"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say yes here to build support for the Freescale FXAS21002C Gyroscope
+ driver connected via I2C.
+
+ This driver can also be built as a module. If so, the module
+ will be called fxas21002c.
+
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
index 295ec780c4eb..ec3e2aeae92a 100644
--- a/drivers/iio/gyro/Makefile
+++ b/drivers/iio/gyro/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_ADXRS450) += adxrs450.o
obj-$(CONFIG_BMG160) += bmg160_core.o
obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o
obj-$(CONFIG_BMG160_SPI) += bmg160_spi.o
+obj-$(CONFIG_FXAS21002C) += fxas21002c.o
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
diff --git a/drivers/iio/gyro/fxas21002c.c b/drivers/iio/gyro/fxas21002c.c
new file mode 100644
index 000000000000..649316c26f5b
--- /dev/null
+++ b/drivers/iio/gyro/fxas21002c.c
@@ -0,0 +1,378 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * FXAS21002C - Digital Angular Rate Gyroscope driver
+ *
+ * Copyright (c) 2018, Afonso Bordado <[email protected]>
+ *
+ * IIO driver for FXAS21002C (7-bit I2C slave address 0x20 or 0x21).
+ * Datasheet: https://www.nxp.com/docs/en/data-sheet/FXAS21002.pdf
+ * TODO:
+ * ODR / Scale Support
+ * Devicetree
+ * Scale Boost Mode
+ * Power management
+ * GPIO Reset
+ * Power supplies
+ * Mount Matrix
+ * LowPass/HighPass Filters
+ * Buffers
+ * Interrupts
+ * Alarms
+ * SPI Support
+ */
+
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#define FXAS21002C_DRV_NAME "fxas21002c"
+
+#define FXAS21002C_MAX_TRANSITION_TIME_MS 61
+
+#define FXAS21002C_CHIP_ID 0xD7
+
+#define FXAS21002C_REG_STATUS 0x00
+#define FXAS21002C_REG_OUT_X_MSB 0x01
+#define FXAS21002C_REG_OUT_X_LSB 0x02
+#define FXAS21002C_REG_OUT_Y_MSB 0x03
+#define FXAS21002C_REG_OUT_Y_LSB 0x04
+#define FXAS21002C_REG_OUT_Z_MSB 0x05
+#define FXAS21002C_REG_OUT_Z_LSB 0x06
+#define FXAS21002C_REG_DR_STATUS 0x07
+#define FXAS21002C_REG_F_STATUS 0x08
+#define FXAS21002C_REG_F_SETUP 0x09
+#define FXAS21002C_REG_F_EVENT 0x0A
+#define FXAS21002C_REG_INT_SRC_FLAG 0x0B
+#define FXAS21002C_REG_WHO_AM_I 0x0C
+
+#define FXAS21002C_REG_CTRL_REG0 0x0D
+#define FXAS21002C_SCALE_MASK GENMASK(1, 0)
+
+#define FXAS21002C_REG_RT_CFG 0x0E
+#define FXAS21002C_REG_RT_SRC 0x0F
+#define FXAS21002C_REG_RT_THS 0x10
+#define FXAS21002C_REG_RT_COUNT 0x11
+#define FXAS21002C_REG_TEMP 0x12
+
+#define FXAS21002C_REG_CTRL_REG1 0x13
+#define FXAS21002C_RST_BIT BIT(6)
+#define FXAS21002C_ACTIVE_BIT BIT(1)
+#define FXAS21002C_READY_BIT BIT(0)
+
+#define FXAS21002C_ODR_SHIFT 2
+#define FXAS21002C_ODR_MASK GENMASK(4, 2)
+
+#define FXAS21002C_REG_CTRL_REG2 0x14
+#define FXAS21002C_REG_CTRL_REG3 0x15
+
+#define FXAS21002C_DEFAULT_ODR_HZ 800
+
+/* 0.0625 deg/s */
+#define FXAS21002C_DEFAULT_SENSITIVITY IIO_DEGREE_TO_RAD(62500)
+
+#define FXAS21002C_TEMP_SCALE 1000
+
+enum {
+ ID_FXAS21002C,
+};
+
+enum fxas21002c_operating_mode {
+ FXAS21002C_OM_BOOT,
+ FXAS21002C_OM_STANDBY,
+ FXAS21002C_OM_READY,
+ FXAS21002C_OM_ACTIVE,
+};
+
+struct fxas21002c_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+};
+
+static const struct regmap_range fxas21002c_writable_ranges[] = {
+ regmap_reg_range(FXAS21002C_REG_F_SETUP, FXAS21002C_REG_F_SETUP),
+ regmap_reg_range(FXAS21002C_REG_CTRL_REG0, FXAS21002C_REG_RT_CFG),
+ regmap_reg_range(FXAS21002C_REG_RT_THS, FXAS21002C_REG_RT_COUNT),
+ regmap_reg_range(FXAS21002C_REG_CTRL_REG1, FXAS21002C_REG_CTRL_REG3),
+};
+
+static const struct regmap_access_table fxas21002c_writable_table = {
+ .yes_ranges = fxas21002c_writable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(fxas21002c_writable_ranges),
+};
+
+static const struct regmap_range fxas21002c_volatile_ranges[] = {
+ regmap_reg_range(FXAS21002C_REG_STATUS, FXAS21002C_REG_F_STATUS),
+ regmap_reg_range(FXAS21002C_REG_F_EVENT, FXAS21002C_REG_INT_SRC_FLAG),
+ regmap_reg_range(FXAS21002C_REG_RT_COUNT, FXAS21002C_REG_CTRL_REG1),
+};
+
+static const struct regmap_access_table fxas21002c_volatile_table = {
+ .yes_ranges = fxas21002c_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(fxas21002c_volatile_ranges),
+};
+
+const struct regmap_config fxas21002c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = FXAS21002C_REG_CTRL_REG3,
+ /* We don't specify a .rd_table because everything is readable */
+ .wr_table = &fxas21002c_writable_table,
+ .volatile_table = &fxas21002c_volatile_table,
+};
+
+#define FXAS21002C_GYRO_CHAN(_axis) { \
+ .type = IIO_ANGL_VEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## _axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .address = FXAS21002C_REG_OUT_ ## _axis ## _MSB, \
+}
+
+static const struct iio_chan_spec fxas21002c_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .address = FXAS21002C_REG_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+ FXAS21002C_GYRO_CHAN(X),
+ FXAS21002C_GYRO_CHAN(Y),
+ FXAS21002C_GYRO_CHAN(Z),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static int fxas21002c_set_operating_mode(struct fxas21002c_data *data,
+ enum fxas21002c_operating_mode om)
+{
+ int ret;
+ int mask;
+
+ switch (om) {
+ case FXAS21002C_OM_STANDBY:
+ mask = 0;
+ break;
+ case FXAS21002C_OM_READY:
+ mask = FXAS21002C_READY_BIT;
+ break;
+ case FXAS21002C_OM_ACTIVE:
+ mask = FXAS21002C_ACTIVE_BIT;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_write(data->regmap, FXAS21002C_REG_CTRL_REG1, mask);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "could not switch operating mode\n");
+ return ret;
+ }
+
+ msleep(FXAS21002C_MAX_TRANSITION_TIME_MS);
+
+ return 0;
+}
+
+static void fxas21002c_standby(void *_data)
+{
+ struct fxas21002c_data *data = _data;
+
+ fxas21002c_set_operating_mode(data, FXAS21002C_OM_STANDBY);
+}
+
+static int fxas21002c_reset(struct fxas21002c_data *data)
+{
+ int ret;
+
+ /*
+ * On issuing a Software Reset command over an I2C interface,
+ * the device immediately resets and does not send any
+ * acknowledgment (ACK) of the written byte to the Master.
+ *
+ * This is documented in table 46 on the datasheet. Due to this
+ * the write will fail with EREMOTEIO.
+ */
+ ret = regmap_write(data->regmap,
+ FXAS21002C_REG_CTRL_REG1, FXAS21002C_RST_BIT);
+
+ if (ret != -EREMOTEIO) {
+ dev_err(&data->client->dev, "could not reset device\n");
+ return ret;
+ }
+
+ regcache_mark_dirty(data->regmap);
+
+ /* Wait for device to boot up */
+ msleep(FXAS21002C_MAX_TRANSITION_TIME_MS);
+
+ return 0;
+}
+
+static int fxas21002c_verify_chip(struct fxas21002c_data *data)
+{
+ int ret;
+ unsigned int chip_id;
+
+ ret = regmap_read(data->regmap, FXAS21002C_REG_WHO_AM_I, &chip_id);
+ if (ret) {
+ dev_err(&data->client->dev, "could not read device id\n");
+ return ret;
+ }
+
+ if (chip_id != FXAS21002C_CHIP_ID) {
+ dev_err(&data->client->dev,
+ "unsupported chip id %02x\n", chip_id);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int fxas21002c_read_oneshot(struct fxas21002c_data *data,
+ struct iio_chan_spec const *chan, int *val)
+{
+ int ret;
+ __be16 bulk_raw;
+ unsigned int uval;
+
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ ret = regmap_bulk_read(data->regmap, chan->address,
+ &bulk_raw, sizeof(bulk_raw));
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(be16_to_cpu(bulk_raw), 15);
+ return IIO_VAL_INT;
+ case IIO_TEMP:
+ ret = regmap_read(data->regmap, chan->address, &uval);
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(uval, 7);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int fxas21002c_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct fxas21002c_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return fxas21002c_read_oneshot(data, chan, val);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ *val = 0;
+ *val2 = FXAS21002C_DEFAULT_SENSITIVITY;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_TEMP:
+ *val = FXAS21002C_TEMP_SCALE;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (chan->type != IIO_ANGL_VEL)
+ return -EINVAL;
+
+ *val = FXAS21002C_DEFAULT_ODR_HZ;
+
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info fxas21002c_info = {
+ .read_raw = fxas21002c_read_raw,
+};
+
+static int fxas21002c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct fxas21002c_data *data;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, indio_dev);
+ data = iio_priv(indio_dev);
+ data->client = client;
+
+ data->regmap = devm_regmap_init_i2c(client, &fxas21002c_regmap_config);
+ if (IS_ERR(data->regmap)) {
+ ret = PTR_ERR(data->regmap);
+ dev_err(&client->dev,
+ "Failed to allocate regmap, err: %d\n", ret);
+ return ret;
+ }
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = fxas21002c_channels;
+ indio_dev->num_channels = ARRAY_SIZE(fxas21002c_channels);
+ indio_dev->name = id->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &fxas21002c_info;
+
+ ret = fxas21002c_verify_chip(data);
+ if (ret < 0)
+ return ret;
+
+ ret = fxas21002c_reset(data);
+ if (ret < 0)
+ return ret;
+
+ ret = fxas21002c_set_operating_mode(data, FXAS21002C_OM_ACTIVE);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_add_action(&client->dev, fxas21002c_standby, data);
+ if (ret < 0) {
+ fxas21002c_standby(data);
+ dev_err(&client->dev, "failed to add standby action\n");
+ return ret;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ dev_err(&client->dev, "failed to register iio device\n");
+
+ return ret;
+}
+
+static const struct i2c_device_id fxas21002c_id[] = {
+ {"fxas21002c", ID_FXAS21002C},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, fxas21002c_id);
+
+static struct i2c_driver fxas21002c_driver = {
+ .driver = {
+ .name = FXAS21002C_DRV_NAME,
+ },
+ .probe = fxas21002c_probe,
+ .id_table = fxas21002c_id,
+};
+
+module_i2c_driver(fxas21002c_driver);
+
+MODULE_AUTHOR("Afonso Bordado <[email protected]>");
+MODULE_DESCRIPTION("FXAS21002C Digital Angular Rate Gyroscope driver");
+MODULE_LICENSE("GPL v2");
--
2.18.0
This patch adds device tree support for the fxas21002c driver.
Signed-off-by: Afonso Bordado <[email protected]>
---
drivers/iio/gyro/fxas21002c.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/iio/gyro/fxas21002c.c b/drivers/iio/gyro/fxas21002c.c
index 649316c26f5b..e2ce0622944b 100644
--- a/drivers/iio/gyro/fxas21002c.c
+++ b/drivers/iio/gyro/fxas21002c.c
@@ -8,7 +8,6 @@
* Datasheet: https://www.nxp.com/docs/en/data-sheet/FXAS21002.pdf
* TODO:
* ODR / Scale Support
- * Devicetree
* Scale Boost Mode
* Power management
* GPIO Reset
@@ -357,6 +356,12 @@ static int fxas21002c_probe(struct i2c_client *client,
return ret;
}
+static const struct of_device_id fxas21002c_of_ids[] = {
+ {.compatible = "fsl,fxas21002c"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, fxas21002c_of_ids);
+
static const struct i2c_device_id fxas21002c_id[] = {
{"fxas21002c", ID_FXAS21002C},
{}
@@ -366,6 +371,7 @@ MODULE_DEVICE_TABLE(i2c, fxas21002c_id);
static struct i2c_driver fxas21002c_driver = {
.driver = {
.name = FXAS21002C_DRV_NAME,
+ .of_match_table = fxas21002c_of_ids,
},
.probe = fxas21002c_probe,
.id_table = fxas21002c_id,
--
2.18.0
Add documentation for the fxas21002c I2C bindings.
Signed-off-by: Afonso Bordado <[email protected]>
---
.../bindings/iio/gyroscope/fsl,fxas21002c.txt | 33 +++++++++++++++++++
1 file changed, 33 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
diff --git a/Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt b/Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
new file mode 100644
index 000000000000..9e5cdf0c0b69
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
@@ -0,0 +1,33 @@
+* Freescale FXAS21002C Digital Angular Rate Gyroscope
+
+Required properties:
+
+ - compatible: must be "fsl,fxas21002c"
+ - reg : the I2C address of the sensor
+
+Optional properties:
+
+ - interrupts : The first interrupt listed must be the one
+ connected to the INT1 pin, the second interrupt
+ listed must be the one connected to the INT2 pin.
+ The interrupts can be triggered on rising or falling
+ edges alike.
+ see interrupt-controller/interrupts.txt
+ - vdd-supply : The main voltage regulator
+ - iovdd-supply : The IO voltage regulator
+ see regulator/regulator.txt
+ - reset-gpios : GPIO used to reset the device.
+ see gpio/gpio.txt.
+ - mount-matrix : see iio/mount-matrix.txt
+
+Example:
+gyroscope@20 {
+ compatible = "fsl,fxas21002c";
+ reg = <0x20>;
+ reset-gpios = <&gpio0 2 0>;
+ vdd-supply = <&vref>;
+ iovdd-supply = <&vref2>;
+ interrupt-parent = <&foo>;
+ interrupts = <0 IRQ_TYPE_EDGE_RISING>,
+ <1 (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)>;
+};
--
2.18.0
This patch adds support for reading/writing ODR/Scale
We don't support the scale boost modes.
Signed-off-by: Afonso Bordado <[email protected]>
---
drivers/iio/gyro/fxas21002c.c | 143 +++++++++++++++++++++++++++++++---
1 file changed, 131 insertions(+), 12 deletions(-)
diff --git a/drivers/iio/gyro/fxas21002c.c b/drivers/iio/gyro/fxas21002c.c
index e2ce0622944b..ea9934b91789 100644
--- a/drivers/iio/gyro/fxas21002c.c
+++ b/drivers/iio/gyro/fxas21002c.c
@@ -7,7 +7,6 @@
* IIO driver for FXAS21002C (7-bit I2C slave address 0x20 or 0x21).
* Datasheet: https://www.nxp.com/docs/en/data-sheet/FXAS21002.pdf
* TODO:
- * ODR / Scale Support
* Scale Boost Mode
* Power management
* GPIO Reset
@@ -66,12 +65,14 @@
#define FXAS21002C_REG_CTRL_REG2 0x14
#define FXAS21002C_REG_CTRL_REG3 0x15
-#define FXAS21002C_DEFAULT_ODR_HZ 800
+#define FXAS21002C_TEMP_SCALE 1000
-/* 0.0625 deg/s */
-#define FXAS21002C_DEFAULT_SENSITIVITY IIO_DEGREE_TO_RAD(62500)
-#define FXAS21002C_TEMP_SCALE 1000
+#define FXAS21002C_SCALE(scale) (IIO_DEGREE_TO_RAD(62500 >> (scale)))
+
+#define FXAS21002C_SAMPLE_FREQ(odr) (800 >> (odr))
+#define FXAS21002C_SAMPLE_FREQ_MICRO(odr) ( \
+ ((odr) == FXAS21002C_ODR_12_5) ? 500000 : 0)
enum {
ID_FXAS21002C,
@@ -89,6 +90,25 @@ struct fxas21002c_data {
struct regmap *regmap;
};
+enum fxas21002c_scale {
+ FXAS21002C_SCALE_62MDPS,
+ FXAS21002C_SCALE_31MDPS,
+ FXAS21002C_SCALE_15MDPS,
+ FXAS21002C_SCALE_7MDPS,
+ __FXAS21002C_SCALE_MAX,
+};
+
+enum fxas21002c_odr {
+ FXAS21002C_ODR_800,
+ FXAS21002C_ODR_400,
+ FXAS21002C_ODR_200,
+ FXAS21002C_ODR_100,
+ FXAS21002C_ODR_50,
+ FXAS21002C_ODR_25,
+ FXAS21002C_ODR_12_5,
+ __FXAS21002C_ODR_MAX,
+};
+
static const struct regmap_range fxas21002c_writable_ranges[] = {
regmap_reg_range(FXAS21002C_REG_F_SETUP, FXAS21002C_REG_F_SETUP),
regmap_reg_range(FXAS21002C_REG_CTRL_REG0, FXAS21002C_REG_RT_CFG),
@@ -261,6 +281,49 @@ static int fxas21002c_read_oneshot(struct fxas21002c_data *data,
}
}
+static int fxas21002c_scale_read(struct fxas21002c_data *data, int *val,
+ int *val2)
+{
+ int ret;
+ unsigned int raw;
+
+ ret = regmap_read(data->regmap, FXAS21002C_REG_CTRL_REG0, &raw);
+ if (ret)
+ return ret;
+
+ raw &= FXAS21002C_SCALE_MASK;
+
+ *val = 0;
+ *val2 = FXAS21002C_SCALE(raw);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int fxas21002c_odr_read(struct fxas21002c_data *data, int *val,
+ int *val2)
+{
+ int ret;
+ unsigned int raw;
+
+ ret = regmap_read(data->regmap, FXAS21002C_REG_CTRL_REG1, &raw);
+ if (ret)
+ return ret;
+
+ raw = (raw & FXAS21002C_ODR_MASK) >> FXAS21002C_ODR_SHIFT;
+
+ /*
+ * We don't use this mode but according to the datasheet its
+ * also a 12.5Hz
+ */
+ if (raw == 7)
+ raw = FXAS21002C_ODR_12_5;
+
+ *val = FXAS21002C_SAMPLE_FREQ(raw);
+ *val2 = FXAS21002C_SAMPLE_FREQ_MICRO(raw);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
static int fxas21002c_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
@@ -273,10 +336,7 @@ static int fxas21002c_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
- *val = 0;
- *val2 = FXAS21002C_DEFAULT_SENSITIVITY;
-
- return IIO_VAL_INT_PLUS_MICRO;
+ return fxas21002c_scale_read(data, val, val2);
case IIO_TEMP:
*val = FXAS21002C_TEMP_SCALE;
@@ -288,16 +348,75 @@ static int fxas21002c_read_raw(struct iio_dev *indio_dev,
if (chan->type != IIO_ANGL_VEL)
return -EINVAL;
- *val = FXAS21002C_DEFAULT_ODR_HZ;
-
- return IIO_VAL_INT;
+ return fxas21002c_odr_read(data, val, val2);
}
return -EINVAL;
}
+
+static int fxas21002c_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct fxas21002c_data *data = iio_priv(indio_dev);
+ int ret = -EINVAL;
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ for (i = 0; i < __FXAS21002C_ODR_MAX; i++) {
+ if (FXAS21002C_SAMPLE_FREQ(i) == val &&
+ FXAS21002C_SAMPLE_FREQ_MICRO(i) == val2)
+ break;
+ }
+
+ if (i == __FXAS21002C_ODR_MAX)
+ break;
+
+ return regmap_update_bits(data->regmap,
+ FXAS21002C_REG_CTRL_REG1,
+ FXAS21002C_ODR_MASK,
+ i << FXAS21002C_ODR_SHIFT);
+ case IIO_CHAN_INFO_SCALE:
+ for (i = 0; i < __FXAS21002C_SCALE_MAX; i++) {
+ if (val == 0 && FXAS21002C_SCALE(i) == val2)
+ break;
+ }
+
+ if (i == __FXAS21002C_SCALE_MAX)
+ break;
+
+ return regmap_update_bits(data->regmap,
+ FXAS21002C_REG_CTRL_REG0,
+ FXAS21002C_SCALE_MASK, i);
+ }
+
+ return ret;
+}
+
+static IIO_CONST_ATTR(anglevel_scale_available,
+ "0.001090831 " /* 62.5 mdps */
+ "0.000545415 " /* 31.25 mdps */
+ "0.000272708 " /* 15.625 mdps */
+ "0.000136354"); /* 7.8125 mdps */
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("800 400 200 100 50 25 12.5");
+
+static struct attribute *fxas21002c_attributes[] = {
+ &iio_const_attr_anglevel_scale_available.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group fxas21002c_attribute_group = {
+ .attrs = fxas21002c_attributes,
+};
+
static const struct iio_info fxas21002c_info = {
.read_raw = fxas21002c_read_raw,
+ .write_raw = fxas21002c_write_raw,
+ .attrs = &fxas21002c_attribute_group,
};
static int fxas21002c_probe(struct i2c_client *client,
--
2.18.0
Add entry for fxas21002c gyroscope driver and add myself as
maintainer of this driver.
Signed-off-by: Afonso Bordado <[email protected]>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 2b9a364b043d..9420f0a8140d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5718,6 +5718,13 @@ S: Maintained
F: drivers/net/ethernet/freescale/gianfar*
F: Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
+FREESCALE FXAS21002C
+M: Afonso Bordado <[email protected]>
+L: [email protected]
+S: Maintained
+F: drivers/iio/gyro/fxas21002.c
+F: Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
+
FREESCALE GPMI NAND DRIVER
M: Han Xu <[email protected]>
L: [email protected]
--
2.18.0
On Tue, Sep 11, 2018 at 04:00:07PM +0100, Afonso Bordado wrote:
> FXAS21002C is a 3 axis gyroscope with integrated temperature sensor
>
> Signed-off-by: Afonso Bordado <[email protected]>
> ---
> Changes in v4
> - Remove CONFIG_OF ifdefs
> - Remove the use of the of_match_ptr macro
> - Split bindings into a separate patch
> - Remove interrupt-parent from binding documentation
> - Whitespace fixes
> - Remove scale and sample frequency tables
> - Place MAINTAINERS block in correct position
>
> Changes in v3
> - Use unsigned int on regmap functions
> - Remove the export of the regmap config
> - Fix undefined behaviour on dev_err call
> - Minor cleanups
>
> Changes in v2
> - Use ANSI C Comments
> - Minor cleanups
> - More dscriptive devicetree bindings
>
> drivers/iio/gyro/Kconfig | 11 +
> drivers/iio/gyro/Makefile | 1 +
> drivers/iio/gyro/fxas21002c.c | 378 ++++++++++++++++++++++++++++++++++
> 3 files changed, 390 insertions(+)
> create mode 100644 drivers/iio/gyro/fxas21002c.c
>
> diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
> index 3126cf05e6b9..d71e33ea9fa4 100644
> --- a/drivers/iio/gyro/Kconfig
> +++ b/drivers/iio/gyro/Kconfig
> @@ -73,6 +73,17 @@ config BMG160_SPI
> tristate
> select REGMAP_SPI
>
> +config FXAS21002C
> + tristate "Freescale FXAS21002C Gyroscope"
> + depends on I2C
> + select REGMAP_I2C
> + help
> + Say yes here to build support for the Freescale FXAS21002C Gyroscope
> + driver connected via I2C.
> +
> + This driver can also be built as a module. If so, the module
> + will be called fxas21002c.
> +
> config HID_SENSOR_GYRO_3D
> depends on HID_SENSOR_HUB
> select IIO_BUFFER
> diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
> index 295ec780c4eb..ec3e2aeae92a 100644
> --- a/drivers/iio/gyro/Makefile
> +++ b/drivers/iio/gyro/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_ADXRS450) += adxrs450.o
> obj-$(CONFIG_BMG160) += bmg160_core.o
> obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o
> obj-$(CONFIG_BMG160_SPI) += bmg160_spi.o
> +obj-$(CONFIG_FXAS21002C) += fxas21002c.o
>
> obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
>
> diff --git a/drivers/iio/gyro/fxas21002c.c b/drivers/iio/gyro/fxas21002c.c
> new file mode 100644
> index 000000000000..649316c26f5b
> --- /dev/null
> +++ b/drivers/iio/gyro/fxas21002c.c
> @@ -0,0 +1,378 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * FXAS21002C - Digital Angular Rate Gyroscope driver
> + *
> + * Copyright (c) 2018, Afonso Bordado <[email protected]>
> + *
> + * IIO driver for FXAS21002C (7-bit I2C slave address 0x20 or 0x21).
> + * Datasheet: https://www.nxp.com/docs/en/data-sheet/FXAS21002.pdf
> + * TODO:
> + * ODR / Scale Support
> + * Devicetree
> + * Scale Boost Mode
> + * Power management
> + * GPIO Reset
> + * Power supplies
> + * Mount Matrix
> + * LowPass/HighPass Filters
> + * Buffers
> + * Interrupts
> + * Alarms
> + * SPI Support
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +
> +#define FXAS21002C_DRV_NAME "fxas21002c"
> +
> +#define FXAS21002C_MAX_TRANSITION_TIME_MS 61
> +
> +#define FXAS21002C_CHIP_ID 0xD7
> +
> +#define FXAS21002C_REG_STATUS 0x00
> +#define FXAS21002C_REG_OUT_X_MSB 0x01
> +#define FXAS21002C_REG_OUT_X_LSB 0x02
> +#define FXAS21002C_REG_OUT_Y_MSB 0x03
> +#define FXAS21002C_REG_OUT_Y_LSB 0x04
> +#define FXAS21002C_REG_OUT_Z_MSB 0x05
> +#define FXAS21002C_REG_OUT_Z_LSB 0x06
> +#define FXAS21002C_REG_DR_STATUS 0x07
> +#define FXAS21002C_REG_F_STATUS 0x08
> +#define FXAS21002C_REG_F_SETUP 0x09
> +#define FXAS21002C_REG_F_EVENT 0x0A
> +#define FXAS21002C_REG_INT_SRC_FLAG 0x0B
> +#define FXAS21002C_REG_WHO_AM_I 0x0C
> +
> +#define FXAS21002C_REG_CTRL_REG0 0x0D
> +#define FXAS21002C_SCALE_MASK GENMASK(1, 0)
> +
> +#define FXAS21002C_REG_RT_CFG 0x0E
> +#define FXAS21002C_REG_RT_SRC 0x0F
> +#define FXAS21002C_REG_RT_THS 0x10
> +#define FXAS21002C_REG_RT_COUNT 0x11
> +#define FXAS21002C_REG_TEMP 0x12
> +
> +#define FXAS21002C_REG_CTRL_REG1 0x13
> +#define FXAS21002C_RST_BIT BIT(6)
> +#define FXAS21002C_ACTIVE_BIT BIT(1)
> +#define FXAS21002C_READY_BIT BIT(0)
> +
> +#define FXAS21002C_ODR_SHIFT 2
> +#define FXAS21002C_ODR_MASK GENMASK(4, 2)
> +
> +#define FXAS21002C_REG_CTRL_REG2 0x14
> +#define FXAS21002C_REG_CTRL_REG3 0x15
> +
> +#define FXAS21002C_DEFAULT_ODR_HZ 800
> +
> +/* 0.0625 deg/s */
> +#define FXAS21002C_DEFAULT_SENSITIVITY IIO_DEGREE_TO_RAD(62500)
> +
> +#define FXAS21002C_TEMP_SCALE 1000
> +
> +enum {
> + ID_FXAS21002C,
> +};
> +
> +enum fxas21002c_operating_mode {
> + FXAS21002C_OM_BOOT,
> + FXAS21002C_OM_STANDBY,
> + FXAS21002C_OM_READY,
> + FXAS21002C_OM_ACTIVE,
> +};
> +
> +struct fxas21002c_data {
> + struct i2c_client *client;
> + struct regmap *regmap;
> +};
> +
> +static const struct regmap_range fxas21002c_writable_ranges[] = {
> + regmap_reg_range(FXAS21002C_REG_F_SETUP, FXAS21002C_REG_F_SETUP),
> + regmap_reg_range(FXAS21002C_REG_CTRL_REG0, FXAS21002C_REG_RT_CFG),
> + regmap_reg_range(FXAS21002C_REG_RT_THS, FXAS21002C_REG_RT_COUNT),
> + regmap_reg_range(FXAS21002C_REG_CTRL_REG1, FXAS21002C_REG_CTRL_REG3),
> +};
> +
> +static const struct regmap_access_table fxas21002c_writable_table = {
> + .yes_ranges = fxas21002c_writable_ranges,
> + .n_yes_ranges = ARRAY_SIZE(fxas21002c_writable_ranges),
> +};
> +
> +static const struct regmap_range fxas21002c_volatile_ranges[] = {
> + regmap_reg_range(FXAS21002C_REG_STATUS, FXAS21002C_REG_F_STATUS),
> + regmap_reg_range(FXAS21002C_REG_F_EVENT, FXAS21002C_REG_INT_SRC_FLAG),
> + regmap_reg_range(FXAS21002C_REG_RT_COUNT, FXAS21002C_REG_CTRL_REG1),
> +};
> +
> +static const struct regmap_access_table fxas21002c_volatile_table = {
> + .yes_ranges = fxas21002c_volatile_ranges,
> + .n_yes_ranges = ARRAY_SIZE(fxas21002c_volatile_ranges),
> +};
> +
> +const struct regmap_config fxas21002c_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> +
> + .max_register = FXAS21002C_REG_CTRL_REG3,
> + /* We don't specify a .rd_table because everything is readable */
> + .wr_table = &fxas21002c_writable_table,
> + .volatile_table = &fxas21002c_volatile_table,
> +};
> +
> +#define FXAS21002C_GYRO_CHAN(_axis) { \
> + .type = IIO_ANGL_VEL, \
> + .modified = 1, \
> + .channel2 = IIO_MOD_ ## _axis, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
> + BIT(IIO_CHAN_INFO_SAMP_FREQ), \
> + .address = FXAS21002C_REG_OUT_ ## _axis ## _MSB, \
> +}
> +
> +static const struct iio_chan_spec fxas21002c_channels[] = {
> + {
> + .type = IIO_TEMP,
> + .address = FXAS21002C_REG_TEMP,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE),
> + },
> + FXAS21002C_GYRO_CHAN(X),
> + FXAS21002C_GYRO_CHAN(Y),
> + FXAS21002C_GYRO_CHAN(Z),
> + IIO_CHAN_SOFT_TIMESTAMP(3),
> +};
> +
> +static int fxas21002c_set_operating_mode(struct fxas21002c_data *data,
> + enum fxas21002c_operating_mode om)
> +{
> + int ret;
> + int mask;
> +
> + switch (om) {
> + case FXAS21002C_OM_STANDBY:
> + mask = 0;
> + break;
> + case FXAS21002C_OM_READY:
> + mask = FXAS21002C_READY_BIT;
> + break;
> + case FXAS21002C_OM_ACTIVE:
> + mask = FXAS21002C_ACTIVE_BIT;
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + ret = regmap_write(data->regmap, FXAS21002C_REG_CTRL_REG1, mask);
> + if (ret) {
> + dev_err(&data->client->dev,
> + "could not switch operating mode\n");
> + return ret;
> + }
> +
> + msleep(FXAS21002C_MAX_TRANSITION_TIME_MS);
> +
> + return 0;
> +}
> +
> +static void fxas21002c_standby(void *_data)
> +{
> + struct fxas21002c_data *data = _data;
> +
> + fxas21002c_set_operating_mode(data, FXAS21002C_OM_STANDBY);
> +}
> +
> +static int fxas21002c_reset(struct fxas21002c_data *data)
> +{
> + int ret;
> +
> + /*
> + * On issuing a Software Reset command over an I2C interface,
> + * the device immediately resets and does not send any
> + * acknowledgment (ACK) of the written byte to the Master.
> + *
> + * This is documented in table 46 on the datasheet. Due to this
> + * the write will fail with EREMOTEIO.
> + */
> + ret = regmap_write(data->regmap,
> + FXAS21002C_REG_CTRL_REG1, FXAS21002C_RST_BIT);
> +
> + if (ret != -EREMOTEIO) {
> + dev_err(&data->client->dev, "could not reset device\n");
> + return ret;
> + }
> +
> + regcache_mark_dirty(data->regmap);
> +
> + /* Wait for device to boot up */
> + msleep(FXAS21002C_MAX_TRANSITION_TIME_MS);
> +
> + return 0;
> +}
> +
> +static int fxas21002c_verify_chip(struct fxas21002c_data *data)
> +{
> + int ret;
> + unsigned int chip_id;
> +
> + ret = regmap_read(data->regmap, FXAS21002C_REG_WHO_AM_I, &chip_id);
> + if (ret) {
> + dev_err(&data->client->dev, "could not read device id\n");
> + return ret;
> + }
> +
> + if (chip_id != FXAS21002C_CHIP_ID) {
> + dev_err(&data->client->dev,
> + "unsupported chip id %02x\n", chip_id);
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +static int fxas21002c_read_oneshot(struct fxas21002c_data *data,
> + struct iio_chan_spec const *chan, int *val)
> +{
> + int ret;
> + __be16 bulk_raw;
> + unsigned int uval;
> +
> + switch (chan->type) {
> + case IIO_ANGL_VEL:
> + ret = regmap_bulk_read(data->regmap, chan->address,
> + &bulk_raw, sizeof(bulk_raw));
> + if (ret)
> + return ret;
> +
> + *val = sign_extend32(be16_to_cpu(bulk_raw), 15);
> + return IIO_VAL_INT;
> + case IIO_TEMP:
> + ret = regmap_read(data->regmap, chan->address, &uval);
> + if (ret)
> + return ret;
> +
> + *val = sign_extend32(uval, 7);
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int fxas21002c_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + struct fxas21002c_data *data = iio_priv(indio_dev);
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + return fxas21002c_read_oneshot(data, chan, val);
> + case IIO_CHAN_INFO_SCALE:
> + switch (chan->type) {
> + case IIO_ANGL_VEL:
> + *val = 0;
> + *val2 = FXAS21002C_DEFAULT_SENSITIVITY;
> +
> + return IIO_VAL_INT_PLUS_MICRO;
> + case IIO_TEMP:
> + *val = FXAS21002C_TEMP_SCALE;
> +
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + if (chan->type != IIO_ANGL_VEL)
> + return -EINVAL;
> +
> + *val = FXAS21002C_DEFAULT_ODR_HZ;
> +
> + return IIO_VAL_INT;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static const struct iio_info fxas21002c_info = {
> + .read_raw = fxas21002c_read_raw,
> +};
> +
> +static int fxas21002c_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + int ret;
> + struct iio_dev *indio_dev;
> + struct fxas21002c_data *data;
> +
> + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + i2c_set_clientdata(client, indio_dev);
> + data = iio_priv(indio_dev);
> + data->client = client;
> +
> + data->regmap = devm_regmap_init_i2c(client, &fxas21002c_regmap_config);
> + if (IS_ERR(data->regmap)) {
> + ret = PTR_ERR(data->regmap);
> + dev_err(&client->dev,
> + "Failed to allocate regmap, err: %d\n", ret);
> + return ret;
> + }
> +
> + indio_dev->dev.parent = &client->dev;
> + indio_dev->channels = fxas21002c_channels;
> + indio_dev->num_channels = ARRAY_SIZE(fxas21002c_channels);
> + indio_dev->name = id->name;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->info = &fxas21002c_info;
> +
> + ret = fxas21002c_verify_chip(data);
> + if (ret < 0)
> + return ret;
> +
> + ret = fxas21002c_reset(data);
> + if (ret < 0)
> + return ret;
> +
> + ret = fxas21002c_set_operating_mode(data, FXAS21002C_OM_ACTIVE);
> + if (ret < 0)
> + return ret;
> +
> + ret = devm_add_action(&client->dev, fxas21002c_standby, data);
> + if (ret < 0) {
> + fxas21002c_standby(data);
> + dev_err(&client->dev, "failed to add standby action\n");
> + return ret;
> + }
> +
> + ret = iio_device_register(indio_dev);
> + if (ret < 0)
> + dev_err(&client->dev, "failed to register iio device\n");
> +
> + return ret;
> +}
> +
> +static const struct i2c_device_id fxas21002c_id[] = {
> + {"fxas21002c", ID_FXAS21002C},
> + {}
> +};
> +MODULE_DEVICE_TABLE(i2c, fxas21002c_id);
> +
> +static struct i2c_driver fxas21002c_driver = {
> + .driver = {
> + .name = FXAS21002C_DRV_NAME,
> + },
> + .probe = fxas21002c_probe,
Hi Afonso,
Andy shevchenko reviewed my patch and told me that we should place with
probe_new() with probe(), and in the declaration of this struct probe is
commented depracated. And I think you might need to replace it, too.
yours,
Song Qiang
> + .id_table = fxas21002c_id,
> +};
> +
> +module_i2c_driver(fxas21002c_driver);
> +
> +MODULE_AUTHOR("Afonso Bordado <[email protected]>");
> +MODULE_DESCRIPTION("FXAS21002C Digital Angular Rate Gyroscope driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.18.0
>
>
Hi Afonso,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on iio/togreg]
[also build test ERROR on v4.19-rc3 next-20180912]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Afonso-Bordado/iio-gyro-add-support-for-fxas21002c/20180912-084443
base: https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
config: i386-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All errors (new ones prefixed by >>):
>> ERROR: "__divdi3" [drivers/iio/gyro/fxas21002c.ko] undefined!
>> ERROR: "__udivdi3" [drivers/iio/gyro/fxas21002c.ko] undefined!
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hello Afonso,
On Wed, Sep 12, 2018 at 05:26:01PM +0800, kbuild test robot wrote:
> Hi Afonso,
>
> Thank you for the patch! Yet something to improve:
>
> [auto build test ERROR on iio/togreg]
> [also build test ERROR on v4.19-rc3 next-20180912]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Afonso-Bordado/iio-gyro-add-support-for-fxas21002c/20180912-084443
> base: https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
> config: i386-allmodconfig (attached as .config)
> compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=i386
>
> All errors (new ones prefixed by >>):
>
> >> ERROR: "__divdi3" [drivers/iio/gyro/fxas21002c.ko] undefined!
> >> ERROR: "__udivdi3" [drivers/iio/gyro/fxas21002c.ko] undefined!
Hmm. This is nasty error that had hit me back and occurs when you
do 64 bit arithmetic in your code and assume it will also build for
32 bit environment(i386).
https://lists.01.org/pipermail/kbuild-all/2018-July/050481.html
But looking at the code seems like there is no such 64 bit division
which is why 0-day didn't inform you the exact line of error unlike
my case in above link.
And I suspect it may be originating from your code snippet:
#define FXAS21002C_SCALE(scale) (IIO_DEGREE_TO_RAD(62500U >> (scale)))
and looking at the implementation:
include/linux/iio/iio.h
/**
* IIO_DEGREE_TO_RAD() - Convert degree to rad
* @deg: A value in degree
*
* Returns the given value converted from degree to rad
*/
#define IIO_DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) / 18000000ULL)
This '/' operator might be the culprit!
Just for checking that the error, remove the macro declaration `FXAS21002C_SCALE`
plus its usage and re-cross compile using `make ARCH=i386`.
In my case I used the `div64_s64` function handles builds for both 32/64
arch accordingly.
Thanks
--
Himanshu Jha
Undergraduate Student
Department of Electronics & Communication
Guru Tegh Bahadur Institute of Technology
Hi,
Thanks for your help with this.
> And I suspect it may be originating from your code snippet:
>
> #define FXAS21002C_SCALE(scale) (IIO_DEGREE_TO_RAD(62500U >>
> (scale)))
>
> and looking at the implementation:
>
> include/linux/iio/iio.h
> /**
> * IIO_DEGREE_TO_RAD() - Convert degree to rad
> * @deg: A value in degree
> *
> * Returns the given value converted from degree to rad
> */
> #define IIO_DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) /
> 18000000ULL)
>
> This '/' operator might be the culprit!
>
> Just for checking that the error, remove the macro declaration
> `FXAS21002C_SCALE`
> plus its usage and re-cross compile using `make ARCH=i386`.
>
> In my case I used the `div64_s64` function handles builds for both
> 32/64
> arch accordingly.
Yes, this is indeed the culprit. If `div64_s64` works the same way, I
wonder if the best option is to change the macro definition.
I can provide a patch for this along with changing the rest of the
definitions. However i would like some confirmation before starting
this.
On Fri, Sep 14, 2018 at 04:26:44PM +0100, Afonso Bordado wrote:
> Hi,
>
> Thanks for your help with this.
>
> > And I suspect it may be originating from your code snippet:
> >
> > #define FXAS21002C_SCALE(scale) (IIO_DEGREE_TO_RAD(62500U >>
> > (scale)))
> >
> > and looking at the implementation:
> >
> > include/linux/iio/iio.h
> > /**
> > * IIO_DEGREE_TO_RAD() - Convert degree to rad
> > * @deg: A value in degree
> > *
> > * Returns the given value converted from degree to rad
> > */
> > #define IIO_DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) /
> > 18000000ULL)
> >
> > This '/' operator might be the culprit!
> >
> > Just for checking that the error, remove the macro declaration
> > `FXAS21002C_SCALE`
> > plus its usage and re-cross compile using `make ARCH=i386`.
> >
> > In my case I used the `div64_s64` function handles builds for both
> > 32/64
> > arch accordingly.
>
> Yes, this is indeed the culprit. If `div64_s64` works the same way, I
> wonder if the best option is to change the macro definition.
"....works the same way" ?
Let us assume that the problem arises due to the 64 bit division, in
which gcc places the __divdi3() runtime function to promote the
"freestanding" environment implementation. And then linking fails
due to unavailability of definitions/declarations of the aforementioned
function.
With `div64_s64` usgae the linker binds the definition present at lib/div64.c
and the build completes successfully whether building for 32/64 bit
environment.
But then why didn't this error showed up in the past, in the rest
of the drivers ?
I see its wide usage in IIO without bug reports:
himanshu@himanshu-Vostro-3559:~/linux-next$ git grep -w "IIO_DEGREE_TO_RAD" drivers/iio/ | wc -l
34
And that concludes, that there is some problem within your code!
In the meantime, you can try to look the disassembly of the function
where this macro is actually used and search for __divdi3/__udivdi3
function referenced in the plt.
I might be wrong though...
Wait a while for the experts to join in!
--
Himanshu Jha
Undergraduate Student
Department of Electronics & Communication
Guru Tegh Bahadur Institute of Technology
On Fri, 14 Sep 2018 23:00:58 +0530
Himanshu Jha <[email protected]> wrote:
> On Fri, Sep 14, 2018 at 04:26:44PM +0100, Afonso Bordado wrote:
> > Hi,
> >
> > Thanks for your help with this.
> >
> > > And I suspect it may be originating from your code snippet:
> > >
> > > #define FXAS21002C_SCALE(scale) (IIO_DEGREE_TO_RAD(62500U >>
> > > (scale)))
> > >
> > > and looking at the implementation:
> > >
> > > include/linux/iio/iio.h
> > > /**
> > > * IIO_DEGREE_TO_RAD() - Convert degree to rad
> > > * @deg: A value in degree
> > > *
> > > * Returns the given value converted from degree to rad
> > > */
> > > #define IIO_DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) /
> > > 18000000ULL)
> > >
> > > This '/' operator might be the culprit!
> > >
> > > Just for checking that the error, remove the macro declaration
> > > `FXAS21002C_SCALE`
> > > plus its usage and re-cross compile using `make ARCH=i386`.
> > >
> > > In my case I used the `div64_s64` function handles builds for both
> > > 32/64
> > > arch accordingly.
> >
> > Yes, this is indeed the culprit. If `div64_s64` works the same way, I
> > wonder if the best option is to change the macro definition.
>
> "....works the same way" ?
>
> Let us assume that the problem arises due to the 64 bit division, in
> which gcc places the __divdi3() runtime function to promote the
> "freestanding" environment implementation. And then linking fails
> due to unavailability of definitions/declarations of the aforementioned
> function.
>
> With `div64_s64` usgae the linker binds the definition present at lib/div64.c
> and the build completes successfully whether building for 32/64 bit
> environment.
>
> But then why didn't this error showed up in the past, in the rest
> of the drivers ?
>
> I see its wide usage in IIO without bug reports:
>
> himanshu@himanshu-Vostro-3559:~/linux-next$ git grep -w "IIO_DEGREE_TO_RAD" drivers/iio/ | wc -l
> 34
>
> And that concludes, that there is some problem within your code!
>
> In the meantime, you can try to look the disassembly of the function
> where this macro is actually used and search for __divdi3/__udivdi3
> function referenced in the plt.
>
> I might be wrong though...
>
> Wait a while for the experts to join in!
>
The reason it's not usually a problem is because it is a compile time
constant for all the other drivers and GCC is more than happy to do
it on 32 bit platforms.
Now whilst it looks like you are doing something that needs to be dynamic
there are actually only a few possible values so this is something we
'want' to do at compile time rather than runtime. Just add a look up
table for those 4 values instead of computing the conversion every
time.
Thanks,
Jonathan
On Tue, 11 Sep 2018 16:00:07 +0100
Afonso Bordado <[email protected]> wrote:
> FXAS21002C is a 3 axis gyroscope with integrated temperature sensor
>
> Signed-off-by: Afonso Bordado <[email protected]>
Hi Afonso,
A few little things in here. I would have cleaned them up when applying
if you didn't already have that issue with division in the later patch
to clean up. Easier to apply the series in one go.
Thanks,
Jonathan
> ---
> Changes in v4
> - Remove CONFIG_OF ifdefs
> - Remove the use of the of_match_ptr macro
> - Split bindings into a separate patch
> - Remove interrupt-parent from binding documentation
> - Whitespace fixes
> - Remove scale and sample frequency tables
> - Place MAINTAINERS block in correct position
>
> Changes in v3
> - Use unsigned int on regmap functions
> - Remove the export of the regmap config
> - Fix undefined behaviour on dev_err call
> - Minor cleanups
>
> Changes in v2
> - Use ANSI C Comments
> - Minor cleanups
> - More dscriptive devicetree bindings
>
> drivers/iio/gyro/Kconfig | 11 +
> drivers/iio/gyro/Makefile | 1 +
> drivers/iio/gyro/fxas21002c.c | 378 ++++++++++++++++++++++++++++++++++
> 3 files changed, 390 insertions(+)
> create mode 100644 drivers/iio/gyro/fxas21002c.c
>
> diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
> index 3126cf05e6b9..d71e33ea9fa4 100644
> --- a/drivers/iio/gyro/Kconfig
> +++ b/drivers/iio/gyro/Kconfig
> @@ -73,6 +73,17 @@ config BMG160_SPI
> tristate
> select REGMAP_SPI
>
> +config FXAS21002C
> + tristate "Freescale FXAS21002C Gyroscope"
> + depends on I2C
> + select REGMAP_I2C
> + help
> + Say yes here to build support for the Freescale FXAS21002C Gyroscope
> + driver connected via I2C.
> +
> + This driver can also be built as a module. If so, the module
> + will be called fxas21002c.
> +
> config HID_SENSOR_GYRO_3D
> depends on HID_SENSOR_HUB
> select IIO_BUFFER
> diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
> index 295ec780c4eb..ec3e2aeae92a 100644
> --- a/drivers/iio/gyro/Makefile
> +++ b/drivers/iio/gyro/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_ADXRS450) += adxrs450.o
> obj-$(CONFIG_BMG160) += bmg160_core.o
> obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o
> obj-$(CONFIG_BMG160_SPI) += bmg160_spi.o
> +obj-$(CONFIG_FXAS21002C) += fxas21002c.o
>
> obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
>
> diff --git a/drivers/iio/gyro/fxas21002c.c b/drivers/iio/gyro/fxas21002c.c
> new file mode 100644
> index 000000000000..649316c26f5b
> --- /dev/null
> +++ b/drivers/iio/gyro/fxas21002c.c
> @@ -0,0 +1,378 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * FXAS21002C - Digital Angular Rate Gyroscope driver
> + *
> + * Copyright (c) 2018, Afonso Bordado <[email protected]>
> + *
> + * IIO driver for FXAS21002C (7-bit I2C slave address 0x20 or 0x21).
> + * Datasheet: https://www.nxp.com/docs/en/data-sheet/FXAS21002.pdf
> + * TODO:
> + * ODR / Scale Support
> + * Devicetree
> + * Scale Boost Mode
> + * Power management
> + * GPIO Reset
> + * Power supplies
> + * Mount Matrix
> + * LowPass/HighPass Filters
> + * Buffers
> + * Interrupts
> + * Alarms
> + * SPI Support
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +
> +#define FXAS21002C_DRV_NAME "fxas21002c"
> +
> +#define FXAS21002C_MAX_TRANSITION_TIME_MS 61
> +
> +#define FXAS21002C_CHIP_ID 0xD7
> +
> +#define FXAS21002C_REG_STATUS 0x00
> +#define FXAS21002C_REG_OUT_X_MSB 0x01
> +#define FXAS21002C_REG_OUT_X_LSB 0x02
> +#define FXAS21002C_REG_OUT_Y_MSB 0x03
> +#define FXAS21002C_REG_OUT_Y_LSB 0x04
> +#define FXAS21002C_REG_OUT_Z_MSB 0x05
> +#define FXAS21002C_REG_OUT_Z_LSB 0x06
> +#define FXAS21002C_REG_DR_STATUS 0x07
> +#define FXAS21002C_REG_F_STATUS 0x08
> +#define FXAS21002C_REG_F_SETUP 0x09
> +#define FXAS21002C_REG_F_EVENT 0x0A
> +#define FXAS21002C_REG_INT_SRC_FLAG 0x0B
> +#define FXAS21002C_REG_WHO_AM_I 0x0C
> +
> +#define FXAS21002C_REG_CTRL_REG0 0x0D
> +#define FXAS21002C_SCALE_MASK GENMASK(1, 0)
> +
> +#define FXAS21002C_REG_RT_CFG 0x0E
> +#define FXAS21002C_REG_RT_SRC 0x0F
> +#define FXAS21002C_REG_RT_THS 0x10
> +#define FXAS21002C_REG_RT_COUNT 0x11
> +#define FXAS21002C_REG_TEMP 0x12
> +
> +#define FXAS21002C_REG_CTRL_REG1 0x13
> +#define FXAS21002C_RST_BIT BIT(6)
> +#define FXAS21002C_ACTIVE_BIT BIT(1)
> +#define FXAS21002C_READY_BIT BIT(0)
> +
> +#define FXAS21002C_ODR_SHIFT 2
> +#define FXAS21002C_ODR_MASK GENMASK(4, 2)
> +
> +#define FXAS21002C_REG_CTRL_REG2 0x14
> +#define FXAS21002C_REG_CTRL_REG3 0x15
> +
> +#define FXAS21002C_DEFAULT_ODR_HZ 800
> +
> +/* 0.0625 deg/s */
> +#define FXAS21002C_DEFAULT_SENSITIVITY IIO_DEGREE_TO_RAD(62500)
> +
> +#define FXAS21002C_TEMP_SCALE 1000
> +
> +enum {
> + ID_FXAS21002C,
Why have this when only one entry? Just don't provide
an device data until we support multiple parts in the driver.
> +};
> +
> +enum fxas21002c_operating_mode {
> + FXAS21002C_OM_BOOT,
> + FXAS21002C_OM_STANDBY,
> + FXAS21002C_OM_READY,
> + FXAS21002C_OM_ACTIVE,
> +};
> +
> +struct fxas21002c_data {
> + struct i2c_client *client;
> + struct regmap *regmap;
> +};
> +
> +static const struct regmap_range fxas21002c_writable_ranges[] = {
> + regmap_reg_range(FXAS21002C_REG_F_SETUP, FXAS21002C_REG_F_SETUP),
> + regmap_reg_range(FXAS21002C_REG_CTRL_REG0, FXAS21002C_REG_RT_CFG),
> + regmap_reg_range(FXAS21002C_REG_RT_THS, FXAS21002C_REG_RT_COUNT),
> + regmap_reg_range(FXAS21002C_REG_CTRL_REG1, FXAS21002C_REG_CTRL_REG3),
> +};
> +
> +static const struct regmap_access_table fxas21002c_writable_table = {
> + .yes_ranges = fxas21002c_writable_ranges,
> + .n_yes_ranges = ARRAY_SIZE(fxas21002c_writable_ranges),
> +};
> +
> +static const struct regmap_range fxas21002c_volatile_ranges[] = {
> + regmap_reg_range(FXAS21002C_REG_STATUS, FXAS21002C_REG_F_STATUS),
> + regmap_reg_range(FXAS21002C_REG_F_EVENT, FXAS21002C_REG_INT_SRC_FLAG),
> + regmap_reg_range(FXAS21002C_REG_RT_COUNT, FXAS21002C_REG_CTRL_REG1),
> +};
> +
> +static const struct regmap_access_table fxas21002c_volatile_table = {
> + .yes_ranges = fxas21002c_volatile_ranges,
> + .n_yes_ranges = ARRAY_SIZE(fxas21002c_volatile_ranges),
> +};
> +
> +const struct regmap_config fxas21002c_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> +
> + .max_register = FXAS21002C_REG_CTRL_REG3,
> + /* We don't specify a .rd_table because everything is readable */
> + .wr_table = &fxas21002c_writable_table,
> + .volatile_table = &fxas21002c_volatile_table,
> +};
> +
> +#define FXAS21002C_GYRO_CHAN(_axis) { \
> + .type = IIO_ANGL_VEL, \
> + .modified = 1, \
> + .channel2 = IIO_MOD_ ## _axis, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
> + BIT(IIO_CHAN_INFO_SAMP_FREQ), \
> + .address = FXAS21002C_REG_OUT_ ## _axis ## _MSB, \
> +}
> +
> +static const struct iio_chan_spec fxas21002c_channels[] = {
> + {
> + .type = IIO_TEMP,
> + .address = FXAS21002C_REG_TEMP,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE),
> + },
> + FXAS21002C_GYRO_CHAN(X),
> + FXAS21002C_GYRO_CHAN(Y),
> + FXAS21002C_GYRO_CHAN(Z),
> + IIO_CHAN_SOFT_TIMESTAMP(3),
Timestamp without buffered mode? It won't do anything so drop it.
> +};
> +
> +static int fxas21002c_set_operating_mode(struct fxas21002c_data *data,
> + enum fxas21002c_operating_mode om)
> +{
> + int ret;
> + int mask;
> +
> + switch (om) {
> + case FXAS21002C_OM_STANDBY:
> + mask = 0;
> + break;
> + case FXAS21002C_OM_READY:
> + mask = FXAS21002C_READY_BIT;
> + break;
> + case FXAS21002C_OM_ACTIVE:
> + mask = FXAS21002C_ACTIVE_BIT;
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + ret = regmap_write(data->regmap, FXAS21002C_REG_CTRL_REG1, mask);
> + if (ret) {
> + dev_err(&data->client->dev,
> + "could not switch operating mode\n");
> + return ret;
> + }
> +
> + msleep(FXAS21002C_MAX_TRANSITION_TIME_MS);
> +
> + return 0;
> +}
> +
> +static void fxas21002c_standby(void *_data)
> +{
> + struct fxas21002c_data *data = _data;
> +
> + fxas21002c_set_operating_mode(data, FXAS21002C_OM_STANDBY);
> +}
> +
> +static int fxas21002c_reset(struct fxas21002c_data *data)
> +{
> + int ret;
> +
> + /*
> + * On issuing a Software Reset command over an I2C interface,
> + * the device immediately resets and does not send any
> + * acknowledgment (ACK) of the written byte to the Master.
> + *
> + * This is documented in table 46 on the datasheet. Due to this
> + * the write will fail with EREMOTEIO.
> + */
> + ret = regmap_write(data->regmap,
> + FXAS21002C_REG_CTRL_REG1, FXAS21002C_RST_BIT);
> +
> + if (ret != -EREMOTEIO) {
> + dev_err(&data->client->dev, "could not reset device\n");
> + return ret;
> + }
> +
> + regcache_mark_dirty(data->regmap);
> +
> + /* Wait for device to boot up */
> + msleep(FXAS21002C_MAX_TRANSITION_TIME_MS);
> +
> + return 0;
> +}
> +
> +static int fxas21002c_verify_chip(struct fxas21002c_data *data)
> +{
> + int ret;
> + unsigned int chip_id;
> +
> + ret = regmap_read(data->regmap, FXAS21002C_REG_WHO_AM_I, &chip_id);
> + if (ret) {
> + dev_err(&data->client->dev, "could not read device id\n");
> + return ret;
> + }
> +
> + if (chip_id != FXAS21002C_CHIP_ID) {
> + dev_err(&data->client->dev,
> + "unsupported chip id %02x\n", chip_id);
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +static int fxas21002c_read_oneshot(struct fxas21002c_data *data,
> + struct iio_chan_spec const *chan, int *val)
> +{
> + int ret;
> + __be16 bulk_raw;
> + unsigned int uval;
> +
> + switch (chan->type) {
> + case IIO_ANGL_VEL:
> + ret = regmap_bulk_read(data->regmap, chan->address,
> + &bulk_raw, sizeof(bulk_raw));
> + if (ret)
> + return ret;
> +
> + *val = sign_extend32(be16_to_cpu(bulk_raw), 15);
> + return IIO_VAL_INT;
> + case IIO_TEMP:
> + ret = regmap_read(data->regmap, chan->address, &uval);
> + if (ret)
> + return ret;
> +
> + *val = sign_extend32(uval, 7);
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int fxas21002c_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + struct fxas21002c_data *data = iio_priv(indio_dev);
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + return fxas21002c_read_oneshot(data, chan, val);
> + case IIO_CHAN_INFO_SCALE:
> + switch (chan->type) {
> + case IIO_ANGL_VEL:
> + *val = 0;
> + *val2 = FXAS21002C_DEFAULT_SENSITIVITY;
> +
> + return IIO_VAL_INT_PLUS_MICRO;
> + case IIO_TEMP:
> + *val = FXAS21002C_TEMP_SCALE;
> +
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + if (chan->type != IIO_ANGL_VEL)
> + return -EINVAL;
> +
> + *val = FXAS21002C_DEFAULT_ODR_HZ;
> +
> + return IIO_VAL_INT;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static const struct iio_info fxas21002c_info = {
> + .read_raw = fxas21002c_read_raw,
> +};
> +
> +static int fxas21002c_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + int ret;
> + struct iio_dev *indio_dev;
> + struct fxas21002c_data *data;
> +
> + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + i2c_set_clientdata(client, indio_dev);
> + data = iio_priv(indio_dev);
> + data->client = client;
> +
> + data->regmap = devm_regmap_init_i2c(client, &fxas21002c_regmap_config);
> + if (IS_ERR(data->regmap)) {
> + ret = PTR_ERR(data->regmap);
> + dev_err(&client->dev,
> + "Failed to allocate regmap, err: %d\n", ret);
> + return ret;
> + }
> +
> + indio_dev->dev.parent = &client->dev;
> + indio_dev->channels = fxas21002c_channels;
> + indio_dev->num_channels = ARRAY_SIZE(fxas21002c_channels);
> + indio_dev->name = id->name;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->info = &fxas21002c_info;
> +
> + ret = fxas21002c_verify_chip(data);
> + if (ret < 0)
> + return ret;
> +
> + ret = fxas21002c_reset(data);
> + if (ret < 0)
> + return ret;
> +
> + ret = fxas21002c_set_operating_mode(data, FXAS21002C_OM_ACTIVE);
> + if (ret < 0)
> + return ret;
> +
> + ret = devm_add_action(&client->dev, fxas21002c_standby, data);
> + if (ret < 0) {
> + fxas21002c_standby(data);
> + dev_err(&client->dev, "failed to add standby action\n");
> + return ret;
> + }
> +
> + ret = iio_device_register(indio_dev);
> + if (ret < 0)
> + dev_err(&client->dev, "failed to register iio device\n");
I'm not sure how I missed this before but you are using non
managed functions in probe but don't have a remove to unwind them.
Effectively your driver can't be removed.
Easy fix, devm_iio_device_register here.
> +
> + return ret;
> +}
> +
> +static const struct i2c_device_id fxas21002c_id[] = {
> + {"fxas21002c", ID_FXAS21002C},
> + {}
> +};
> +MODULE_DEVICE_TABLE(i2c, fxas21002c_id);
> +
> +static struct i2c_driver fxas21002c_driver = {
> + .driver = {
> + .name = FXAS21002C_DRV_NAME,
> + },
> + .probe = fxas21002c_probe,
> + .id_table = fxas21002c_id,
> +};
> +
> +module_i2c_driver(fxas21002c_driver);
> +
> +MODULE_AUTHOR("Afonso Bordado <[email protected]>");
> +MODULE_DESCRIPTION("FXAS21002C Digital Angular Rate Gyroscope driver");
> +MODULE_LICENSE("GPL v2");
On Tue, 11 Sep 2018 16:00:09 +0100
Afonso Bordado <[email protected]> wrote:
> Add documentation for the fxas21002c I2C bindings.
>
> Signed-off-by: Afonso Bordado <[email protected]>
Device tree bindings should go to the devicetree maintainers
and the devicetree binding list. Make sure v5 goes
that way.
This one is just about complex enough I'll want a review from
Rob as he is more likely to catch a problem than I am.
Thanks,
Jonathan
> ---
> .../bindings/iio/gyroscope/fsl,fxas21002c.txt | 33 +++++++++++++++++++
> 1 file changed, 33 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
>
> diff --git a/Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt b/Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
> new file mode 100644
> index 000000000000..9e5cdf0c0b69
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
> @@ -0,0 +1,33 @@
> +* Freescale FXAS21002C Digital Angular Rate Gyroscope
> +
> +Required properties:
> +
> + - compatible: must be "fsl,fxas21002c"
> + - reg : the I2C address of the sensor
> +
> +Optional properties:
> +
> + - interrupts : The first interrupt listed must be the one
> + connected to the INT1 pin, the second interrupt
> + listed must be the one connected to the INT2 pin.
> + The interrupts can be triggered on rising or falling
> + edges alike.
> + see interrupt-controller/interrupts.txt
> + - vdd-supply : The main voltage regulator
> + - iovdd-supply : The IO voltage regulator
> + see regulator/regulator.txt
> + - reset-gpios : GPIO used to reset the device.
> + see gpio/gpio.txt.
> + - mount-matrix : see iio/mount-matrix.txt
> +
> +Example:
> +gyroscope@20 {
> + compatible = "fsl,fxas21002c";
> + reg = <0x20>;
> + reset-gpios = <&gpio0 2 0>;
> + vdd-supply = <&vref>;
> + iovdd-supply = <&vref2>;
> + interrupt-parent = <&foo>;
> + interrupts = <0 IRQ_TYPE_EDGE_RISING>,
> + <1 (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)>;
> +};
On Tue, 11 Sep 2018 16:00:09 +0100
Afonso Bordado <[email protected]> wrote:
> Add documentation for the fxas21002c I2C bindings.
>
> Signed-off-by: Afonso Bordado <[email protected]>
> ---
> .../bindings/iio/gyroscope/fsl,fxas21002c.txt | 33 +++++++++++++++++++
> 1 file changed, 33 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
>
> diff --git a/Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt b/Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
> new file mode 100644
> index 000000000000..9e5cdf0c0b69
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/gyroscope/fsl,fxas21002c.txt
> @@ -0,0 +1,33 @@
> +* Freescale FXAS21002C Digital Angular Rate Gyroscope
> +
> +Required properties:
> +
> + - compatible: must be "fsl,fxas21002c"
> + - reg : the I2C address of the sensor
> +
> +Optional properties:
> +
> + - interrupts : The first interrupt listed must be the one
> + connected to the INT1 pin, the second interrupt
> + listed must be the one connected to the INT2 pin.
> + The interrupts can be triggered on rising or falling
> + edges alike.
> + see interrupt-controller/interrupts.txt
> + - vdd-supply : The main voltage regulator
> + - iovdd-supply : The IO voltage regulator
> + see regulator/regulator.txt
> + - reset-gpios : GPIO used to reset the device.
> + see gpio/gpio.txt.
> + - mount-matrix : see iio/mount-matrix.txt
This last one could do with a very brief introduction to what
it is (as well as the cross reference).
This is particularly true as it isn't clear whether it is
necessary or optional. The below doesn't have it there for
example.
> +
> +Example:
> +gyroscope@20 {
> + compatible = "fsl,fxas21002c";
> + reg = <0x20>;
> + reset-gpios = <&gpio0 2 0>;
> + vdd-supply = <&vref>;
> + iovdd-supply = <&vref2>;
> + interrupt-parent = <&foo>;
> + interrupts = <0 IRQ_TYPE_EDGE_RISING>,
> + <1 (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)>;
Perhaps keep these in the same order as in the description above.
> +};