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.
Signed-off-by: Mehdi Djait <mehdi.djait.k@gmail.com>
---
v2:
- mentioned the kx132-1211 in the Kconfig
- added a kx132-specific get_fifo_bytes function
- changed the device name from "kx132" to "kx132-1211"
drivers/iio/accel/Kconfig | 8 +-
drivers/iio/accel/kionix-kx022a-i2c.c | 2 +
drivers/iio/accel/kionix-kx022a-spi.c | 2 +
drivers/iio/accel/kionix-kx022a.c | 145 ++++++++++++++++++++++++++
drivers/iio/accel/kionix-kx022a.h | 52 +++++++++
5 files changed, 205 insertions(+), 4 deletions(-)
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index b6b45d359f28..d8cc6e6f2bb9 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -418,8 +418,8 @@ 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 KX022A, KX132-1211 digital tri-axis
+ accelerometers connected to SPI interface.
config IIO_KX022A_I2C
tristate "Kionix KX022A tri-axis digital accelerometer I2C interface"
@@ -427,8 +427,8 @@ 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 KX022A, KX132-1211 digital tri-axis
+ accelerometers connected to I2C interface.
config KXSD9
tristate "Kionix KXSD9 Accelerometer Driver"
diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c
index ce299d0446f7..4ea28d2482ec 100644
--- a/drivers/iio/accel/kionix-kx022a-i2c.c
+++ b/drivers/iio/accel/kionix-kx022a-i2c.c
@@ -39,12 +39,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);
diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c
index 7bc81588e40e..8441d1444b9d 100644
--- a/drivers/iio/accel/kionix-kx022a-spi.c
+++ b/drivers/iio/accel/kionix-kx022a-spi.c
@@ -39,12 +39,14 @@ static int kx022a_spi_probe(struct spi_device *spi)
static const struct spi_device_id kx022a_spi_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_spi_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);
diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c
index 1c81ea1657b9..f058e266d189 100644
--- a/drivers/iio/accel/kionix-kx022a.c
+++ b/drivers/iio/accel/kionix-kx022a.c
@@ -150,6 +150,99 @@ 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_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,
+ },
+};
+
+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_MAN_WAKE,
+ .range_max = KX132_REG_MAN_WAKE,
+ }, {
+ .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,
};
static const struct iio_mount_matrix *
@@ -206,6 +299,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
@@ -582,6 +682,25 @@ static int kx022a_get_fifo_bytes(struct kx022a_data *data)
return fifo_bytes;
}
+static int kx132_get_fifo_bytes(struct kx022a_data *data)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ __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(dev, "Error reading buffer status\n");
+ return ret;
+ }
+
+ buf_status &= data->chip_info->buf_smp_lvl_mask;
+ fifo_bytes = le16_to_cpu(buf_status);
+
+ return fifo_bytes;
+}
+
static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
bool irq)
{
@@ -1006,6 +1125,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 = kx132_get_fifo_bytes,
+};
+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"};
diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h
index 43e32e688258..c79d9895921e 100644
--- a/drivers/iio/accel/kionix-kx022a.h
+++ b/drivers/iio/accel/kionix-kx022a.h
@@ -76,6 +76,57 @@
#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_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_MAN_WAKE 0x4d
+
+#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 {
@@ -165,5 +216,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
--
2.30.2
Hi Mehdi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on next-20230421]
[cannot apply to linus/master v6.3-rc7]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Mehdi-Djait/dt-bindings-iio-Add-KX132-1211-accelerometer/20230421-042531
base: https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link: https://lore.kernel.org/r/cef09595632a40eff8a0864fea2e0eb6653930a5.1682019544.git.mehdi.djait.k%40gmail.com
patch subject: [PATCH v2 5/5] iio: accel: Add support for Kionix/ROHM KX132-1211 accelerometer
config: mips-randconfig-s031-20230421 (https://download.01.org/0day-ci/archive/20230422/202304220729.FCofPRvH-lkp@intel.com/config)
compiler: mips64-linux-gcc (GCC) 12.1.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.4-39-gce1a6720-dirty
# https://github.com/intel-lab-lkp/linux/commit/38837f58c549d688da8cb7cfb1aea0bd65a12548
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Mehdi-Djait/dt-bindings-iio-Add-KX132-1211-accelerometer/20230421-042531
git checkout 38837f58c549d688da8cb7cfb1aea0bd65a12548
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=mips olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=mips SHELL=/bin/bash drivers/iio/accel/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202304220729.FCofPRvH-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/iio/accel/kionix-kx022a.c:698:20: sparse: sparse: invalid assignment: &=
>> drivers/iio/accel/kionix-kx022a.c:698:20: sparse: left side has type restricted __le16
>> drivers/iio/accel/kionix-kx022a.c:698:20: sparse: right side has type unsigned short
vim +698 drivers/iio/accel/kionix-kx022a.c
684
685 static int kx132_get_fifo_bytes(struct kx022a_data *data)
686 {
687 struct device *dev = regmap_get_device(data->regmap);
688 __le16 buf_status;
689 int ret, fifo_bytes;
690
691 ret = regmap_bulk_read(data->regmap, data->chip_info->buf_status1,
692 &buf_status, sizeof(buf_status));
693 if (ret) {
694 dev_err(dev, "Error reading buffer status\n");
695 return ret;
696 }
697
> 698 buf_status &= data->chip_info->buf_smp_lvl_mask;
699 fifo_bytes = le16_to_cpu(buf_status);
700
701 return fifo_bytes;
702 }
703
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests
On Sat, Apr 22, 2023 at 07:19:44AM +0800, kernel test robot wrote:
> Hi Mehdi,
>
> kernel test robot noticed the following build warnings:
I believe it's not just a warning, it's a full functional error in the code.
> 686 {
> 687 struct device *dev = regmap_get_device(data->regmap);
> 688 __le16 buf_status;
> 689 int ret, fifo_bytes;
> 690
> 691 ret = regmap_bulk_read(data->regmap, data->chip_info->buf_status1,
> 692 &buf_status, sizeof(buf_status));
> 693 if (ret) {
> 694 dev_err(dev, "Error reading buffer status\n");
> 695 return ret;
> 696 }
> 697
> > 698 buf_status &= data->chip_info->buf_smp_lvl_mask;
> 699 fifo_bytes = le16_to_cpu(buf_status);
You need to mask in the same endianess space, i.o.w. either on CPU or device side.
I believe you wanted to have fifo_bytes to be masked, but I'm not sure.
> 701 return fifo_bytes;
> 702 }
--
With Best Regards,
Andy Shevchenko
Hello Andy,
thank you for the review.
On Sat, Apr 22, 2023 at 07:09:12PM +0300, Andy Shevchenko wrote:
> On Sat, Apr 22, 2023 at 07:19:44AM +0800, kernel test robot wrote:
> > Hi Mehdi,
> >
> > kernel test robot noticed the following build warnings:
>
> I believe it's not just a warning, it's a full functional error in the code.
>
> > 686 {
> > 687 struct device *dev = regmap_get_device(data->regmap);
> > 688 __le16 buf_status;
> > 689 int ret, fifo_bytes;
> > 690
> > 691 ret = regmap_bulk_read(data->regmap, data->chip_info->buf_status1,
> > 692 &buf_status, sizeof(buf_status));
> > 693 if (ret) {
> > 694 dev_err(dev, "Error reading buffer status\n");
> > 695 return ret;
> > 696 }
> > 697
> > > 698 buf_status &= data->chip_info->buf_smp_lvl_mask;
> > 699 fifo_bytes = le16_to_cpu(buf_status);
>
> You need to mask in the same endianess space, i.o.w. either on CPU or device side.
>
> I believe you wanted to have fifo_bytes to be masked, but I'm not sure.
I wanted to read the registers buf_status_1 and buf_status_2 --> 16 bits
and mask the result of the read to get the bits 0..9 which is the
buf_status: the number of bytes in the buffer
This is due to my lack of experience, but I have a question:
If I don't get any warnings when testing, how should I go about this ? I
will obviously fix this, but this is for the future.
--
Kind Regards
Mehdi Djait
Hello again,
On Sun, Apr 23, 2023 at 10:57:00PM +0200, Mehdi Djait wrote:
> Hello Andy,
>
> thank you for the review.
>
> On Sat, Apr 22, 2023 at 07:09:12PM +0300, Andy Shevchenko wrote:
> > On Sat, Apr 22, 2023 at 07:19:44AM +0800, kernel test robot wrote:
> > > Hi Mehdi,
> > >
> > > kernel test robot noticed the following build warnings:
> >
> > I believe it's not just a warning, it's a full functional error in the code.
> >
> > > 686 {
> > > 687 struct device *dev = regmap_get_device(data->regmap);
> > > 688 __le16 buf_status;
> > > 689 int ret, fifo_bytes;
> > > 690
> > > 691 ret = regmap_bulk_read(data->regmap, data->chip_info->buf_status1,
> > > 692 &buf_status, sizeof(buf_status));
> > > 693 if (ret) {
> > > 694 dev_err(dev, "Error reading buffer status\n");
> > > 695 return ret;
> > > 696 }
> > > 697
> > > > 698 buf_status &= data->chip_info->buf_smp_lvl_mask;
> > > 699 fifo_bytes = le16_to_cpu(buf_status);
> >
> > You need to mask in the same endianess space, i.o.w. either on CPU or device side.
> >
> > I believe you wanted to have fifo_bytes to be masked, but I'm not sure.
>
> I wanted to read the registers buf_status_1 and buf_status_2 --> 16 bits
> and mask the result of the read to get the bits 0..9 which is the
> buf_status: the number of bytes in the buffer
>
> This is due to my lack of experience, but I have a question:
> If I don't get any warnings when testing, how should I go about this ? I
> will obviously fix this, but this is for the future.
just ignore this question. I installed sparse and I am using it now when
building.
--
Kind Regards
Mehdi Djait
© 2016 - 2025 Red Hat, Inc.