iio: accel: Add support for Kionix/ROHM KX132-1211 accelerometer
authorMehdi Djait <mehdi.djait.k@gmail.com>
Sat, 16 Sep 2023 12:38:53 +0000 (14:38 +0200)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sun, 17 Sep 2023 09:44:57 +0000 (10:44 +0100)
Kionix KX132-1211 is a tri-axis 16-bit accelerometer that can support
ranges from ±2G to ±16G, digital output through I²C/SPI.
Add support for basic accelerometer features such as reading acceleration
via IIO using raw reads, triggered buffer (data-ready), or the WMI IRQ.

Datasheet: https://kionixfs.azureedge.net/en/document/KX132-1211-Technical-Reference-Manual-Rev-5.0.pdf
Acked-by: Matti Vaittinen <mazziesaccount@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Mehdi Djait <mehdi.djait.k@gmail.com>
Link: https://lore.kernel.org/r/389a7d6100ff2e71b1c5d60bebe662d09435996a.1694867379.git.mehdi.djait.k@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/accel/Kconfig
drivers/iio/accel/kionix-kx022a-i2c.c
drivers/iio/accel/kionix-kx022a-spi.c
drivers/iio/accel/kionix-kx022a.c
drivers/iio/accel/kionix-kx022a.h

index b6b45d359f287fa945f8dc80fe048eacdded1323..373257d64a7e2da88dbeefa9ca21ff1abc45304b 100644 (file)
@@ -418,8 +418,9 @@ config IIO_KX022A_SPI
        select IIO_KX022A
        select REGMAP_SPI
        help
-         Enable support for the Kionix KX022A digital tri-axis
-         accelerometer connected to I2C interface.
+         Enable support for the Kionix digital tri-axis accelerometers
+         connected to SPI interface. Supported devices are:
+           KX022A, KX132-1211
 
 config IIO_KX022A_I2C
        tristate "Kionix KX022A tri-axis digital accelerometer I2C interface"
@@ -427,8 +428,9 @@ config IIO_KX022A_I2C
        select IIO_KX022A
        select REGMAP_I2C
        help
-         Enable support for the Kionix KX022A digital tri-axis
-         accelerometer connected to I2C interface.
+         Enable support for the Kionix digital tri-axis accelerometers
+         connected to I2C interface. Supported devices are:
+           KX022A, KX132-1211
 
 config KXSD9
        tristate "Kionix KXSD9 Accelerometer Driver"
index 2fdc4c1ab93f7cbbd26940bb3b25418a62751174..fc53e527cae0de2d9e3eb0138422f08213431f8c 100644 (file)
@@ -37,12 +37,14 @@ static int kx022a_i2c_probe(struct i2c_client *i2c)
 
 static const struct i2c_device_id kx022a_i2c_id[] = {
        { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
+       { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
 
 static const struct of_device_id kx022a_of_match[] = {
        { .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
+       { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(of, kx022a_of_match);
index c21494ade1573672b311a645502a9dbf15256c16..e7878ba678274126a7dc8e2a62246498c9a558b8 100644 (file)
@@ -37,12 +37,14 @@ static int kx022a_spi_probe(struct spi_device *spi)
 
 static const struct spi_device_id kx022a_id[] = {
        { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
+       { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(spi, kx022a_id);
 
 static const struct of_device_id kx022a_of_match[] = {
        { .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
+       { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(of, kx022a_of_match);
index cc7134b1183b35bb9cdaeec6f08e66c3122e1342..c5b555094e605dc07f8d7829d21f50f72ec8835e 100644 (file)
@@ -150,6 +150,117 @@ static const struct regmap_config kx022a_regmap_config = {
        .cache_type = REGCACHE_RBTREE,
 };
 
+/* Regmap configs kx132 */
+static const struct regmap_range kx132_volatile_ranges[] = {
+       {
+               .range_min = KX132_REG_XADP_L,
+               .range_max = KX132_REG_COTR,
+       }, {
+               .range_min = KX132_REG_TSCP,
+               .range_max = KX132_REG_INT_REL,
+       }, {
+               /* The reset bit will be cleared by sensor */
+               .range_min = KX132_REG_CNTL2,
+               .range_max = KX132_REG_CNTL2,
+       }, {
+               .range_min = KX132_REG_CNTL5,
+               .range_max = KX132_REG_CNTL5,
+       }, {
+               .range_min = KX132_REG_BUF_STATUS_1,
+               .range_max = KX132_REG_BUF_READ,
+       },
+};
+
+static const struct regmap_access_table kx132_volatile_regs = {
+       .yes_ranges = &kx132_volatile_ranges[0],
+       .n_yes_ranges = ARRAY_SIZE(kx132_volatile_ranges),
+};
+
+static const struct regmap_range kx132_precious_ranges[] = {
+       {
+               .range_min = KX132_REG_INT_REL,
+               .range_max = KX132_REG_INT_REL,
+       },
+};
+
+static const struct regmap_access_table kx132_precious_regs = {
+       .yes_ranges = &kx132_precious_ranges[0],
+       .n_yes_ranges = ARRAY_SIZE(kx132_precious_ranges),
+};
+
+static const struct regmap_range kx132_read_only_ranges[] = {
+       {
+               .range_min = KX132_REG_XADP_L,
+               .range_max = KX132_REG_INT_REL,
+       }, {
+               .range_min = KX132_REG_BUF_STATUS_1,
+               .range_max = KX132_REG_BUF_STATUS_2,
+       }, {
+               .range_min = KX132_REG_BUF_READ,
+               .range_max = KX132_REG_BUF_READ,
+       }, {
+               /* Kionix reserved registers: should not be written */
+               .range_min = 0x28,
+               .range_max = 0x28,
+       }, {
+               .range_min = 0x35,
+               .range_max = 0x36,
+       }, {
+               .range_min = 0x3c,
+               .range_max = 0x48,
+       }, {
+               .range_min = 0x4e,
+               .range_max = 0x5c,
+       }, {
+               .range_min = 0x77,
+               .range_max = 0x7f,
+       },
+};
+
+static const struct regmap_access_table kx132_ro_regs = {
+       .no_ranges = &kx132_read_only_ranges[0],
+       .n_no_ranges = ARRAY_SIZE(kx132_read_only_ranges),
+};
+
+static const struct regmap_range kx132_write_only_ranges[] = {
+       {
+               .range_min = KX132_REG_SELF_TEST,
+               .range_max = KX132_REG_SELF_TEST,
+       }, {
+               .range_min = KX132_REG_BUF_CLEAR,
+               .range_max = KX132_REG_BUF_CLEAR,
+       },
+};
+
+static const struct regmap_access_table kx132_wo_regs = {
+       .no_ranges = &kx132_write_only_ranges[0],
+       .n_no_ranges = ARRAY_SIZE(kx132_write_only_ranges),
+};
+
+static const struct regmap_range kx132_noinc_read_ranges[] = {
+       {
+               .range_min = KX132_REG_BUF_READ,
+               .range_max = KX132_REG_BUF_READ,
+       },
+};
+
+static const struct regmap_access_table kx132_nir_regs = {
+       .yes_ranges = &kx132_noinc_read_ranges[0],
+       .n_yes_ranges = ARRAY_SIZE(kx132_noinc_read_ranges),
+};
+
+static const struct regmap_config kx132_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .volatile_table = &kx132_volatile_regs,
+       .rd_table = &kx132_wo_regs,
+       .wr_table = &kx132_ro_regs,
+       .rd_noinc_table = &kx132_nir_regs,
+       .precious_table = &kx132_precious_regs,
+       .max_register = KX132_MAX_REGISTER,
+       .cache_type = REGCACHE_RBTREE,
+};
+
 struct kx022a_data {
        struct regmap *regmap;
        const struct kx022a_chip_info *chip_info;
@@ -239,6 +350,13 @@ static const struct iio_chan_spec kx022a_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
+static const struct iio_chan_spec kx132_channels[] = {
+       KX022A_ACCEL_CHAN(X, KX132_REG_XOUT_L, 0),
+       KX022A_ACCEL_CHAN(Y, KX132_REG_YOUT_L, 1),
+       KX022A_ACCEL_CHAN(Z, KX132_REG_ZOUT_L, 2),
+       IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
 /*
  * The sensor HW can support ODR up to 1600 Hz, which is beyond what most of the
  * Linux CPUs can handle without dropping samples. Also, the low power mode is
@@ -601,6 +719,26 @@ static int kx022a_get_fifo_bytes_available(struct kx022a_data *data)
        return fifo_bytes;
 }
 
+static int kx132_get_fifo_bytes_available(struct kx022a_data *data)
+{
+       __le16 buf_status;
+       int ret, fifo_bytes;
+
+       ret = regmap_bulk_read(data->regmap, data->chip_info->buf_status1,
+                              &buf_status, sizeof(buf_status));
+       if (ret) {
+               dev_err(data->dev, "Error reading buffer status\n");
+               return ret;
+       }
+
+       fifo_bytes = le16_to_cpu(buf_status);
+       fifo_bytes &= data->chip_info->buf_smp_lvl_mask;
+       fifo_bytes = min((unsigned int)fifo_bytes, data->chip_info->fifo_length *
+                        KX022A_FIFO_SAMPLES_SIZE_BYTES);
+
+       return fifo_bytes;
+}
+
 static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
                               bool irq)
 {
@@ -1024,6 +1162,32 @@ const struct kx022a_chip_info kx022a_chip_info = {
 };
 EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A);
 
+const struct kx022a_chip_info kx132_chip_info = {
+       .name                     = "kx132-1211",
+       .regmap_config            = &kx132_regmap_config,
+       .channels                 = kx132_channels,
+       .num_channels             = ARRAY_SIZE(kx132_channels),
+       .fifo_length              = KX132_FIFO_LENGTH,
+       .who                      = KX132_REG_WHO,
+       .id                       = KX132_ID,
+       .cntl                     = KX132_REG_CNTL,
+       .cntl2                    = KX132_REG_CNTL2,
+       .odcntl                   = KX132_REG_ODCNTL,
+       .buf_cntl1                = KX132_REG_BUF_CNTL1,
+       .buf_cntl2                = KX132_REG_BUF_CNTL2,
+       .buf_clear                = KX132_REG_BUF_CLEAR,
+       .buf_status1              = KX132_REG_BUF_STATUS_1,
+       .buf_smp_lvl_mask         = KX132_MASK_BUF_SMP_LVL,
+       .buf_read                 = KX132_REG_BUF_READ,
+       .inc1                     = KX132_REG_INC1,
+       .inc4                     = KX132_REG_INC4,
+       .inc5                     = KX132_REG_INC5,
+       .inc6                     = KX132_REG_INC6,
+       .xout_l                   = KX132_REG_XOUT_L,
+       .get_fifo_bytes_available = kx132_get_fifo_bytes_available,
+};
+EXPORT_SYMBOL_NS_GPL(kx132_chip_info, IIO_KX022A);
+
 int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)
 {
        static const char * const regulator_names[] = {"io-vdd", "vdd"};
index 7ca48e6f2c49cb54cf538e88e12299491333dccf..35c548ae7eff0b79733ed87468c2cf067933dda4 100644 (file)
 #define KX022A_REG_SELF_TEST   0x60
 #define KX022A_MAX_REGISTER    0x60
 
+#define KX132_REG_WHO          0x13
+#define KX132_ID               0x3d
+
+#define KX132_FIFO_LENGTH      86
+
+#define KX132_REG_CNTL         0x1b
+#define KX132_REG_CNTL2                0x1c
+#define KX132_REG_CNTL5                0x1f
+#define KX132_MASK_RES         BIT(6)
+#define KX132_GSEL_2           0x0
+#define KX132_GSEL_4           BIT(3)
+#define KX132_GSEL_8           BIT(4)
+#define KX132_GSEL_16          GENMASK(4, 3)
+
+#define KX132_REG_INS2         0x17
+#define KX132_MASK_INS2_WMI    BIT(5)
+
+#define KX132_REG_XADP_L       0x02
+#define KX132_REG_XOUT_L       0x08
+#define KX132_REG_YOUT_L       0x0a
+#define KX132_REG_ZOUT_L       0x0c
+#define KX132_REG_COTR         0x12
+#define KX132_REG_TSCP         0x14
+#define KX132_REG_INT_REL      0x1a
+
+#define KX132_REG_ODCNTL       0x21
+
+#define KX132_REG_BTS_WUF_TH   0x4a
+
+#define KX132_REG_BUF_CNTL1    0x5e
+#define KX132_REG_BUF_CNTL2    0x5f
+#define KX132_REG_BUF_STATUS_1 0x60
+#define KX132_REG_BUF_STATUS_2 0x61
+#define KX132_MASK_BUF_SMP_LVL GENMASK(9, 0)
+#define KX132_REG_BUF_CLEAR    0x62
+#define KX132_REG_BUF_READ     0x63
+#define KX132_ODR_SHIFT                3
+#define KX132_FIFO_MAX_WMI_TH  86
+
+#define KX132_REG_INC1         0x22
+#define KX132_REG_INC5         0x26
+#define KX132_REG_INC6         0x27
+#define KX132_IPOL_LOW         0
+#define KX132_IPOL_HIGH                KX022A_MASK_IPOL
+#define KX132_ITYP_PULSE       KX022A_MASK_ITYP
+
+#define KX132_REG_INC4         0x25
+
+#define KX132_REG_SELF_TEST    0x5d
+#define KX132_MAX_REGISTER     0x76
+
 struct device;
 
 struct kx022a_data;
@@ -86,6 +137,7 @@ struct kx022a_data;
  * @channels:                  pointer to iio_chan_spec array
  * @num_channels:              number of iio_chan_spec channels
  * @fifo_length:               number of 16-bit samples in a full buffer
+ * @buf_smp_lvl_mask:          buffer sample level mask
  * @who:                       WHO_AM_I register
  * @id:                                WHO_AM_I register value
  * @cntl:                      control register 1
@@ -111,6 +163,7 @@ struct kx022a_chip_info {
        const struct iio_chan_spec *channels;
        unsigned int num_channels;
        unsigned int fifo_length;
+       u16 buf_smp_lvl_mask;
        u8 who;
        u8 id;
        u8 cntl;
@@ -132,5 +185,6 @@ struct kx022a_chip_info {
 int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info);
 
 extern const struct kx022a_chip_info kx022a_chip_info;
+extern const struct kx022a_chip_info kx132_chip_info;
 
 #endif