[2/3] iio: accel: kionix-kx022a: Add chip_info structure

Message ID 3ddca10a4c03c3a64afb831cc9dd1e01fe89d305.1679009443.git.mehdi.djait.k@gmail.com
State New
Headers
Series iio: accel: Add support for Kionix/ROHM KX132 accelerometer |

Commit Message

Mehdi Djait March 16, 2023, 11:48 p.m. UTC
  Refactor the kx022a driver implementation to make it more
generic and extensible.
Add the chip_info structure will to the driver's private
data to hold all the device specific infos.
Move the enum, struct and constants definitions to the header
file.

Signed-off-by: Mehdi Djait <mehdi.djait.k@gmail.com>
---
 drivers/iio/accel/kionix-kx022a-i2c.c |  19 +-
 drivers/iio/accel/kionix-kx022a-spi.c |  22 +-
 drivers/iio/accel/kionix-kx022a.c     | 289 ++++++++++++--------------
 drivers/iio/accel/kionix-kx022a.h     | 128 ++++++++++--
 4 files changed, 274 insertions(+), 184 deletions(-)
  

Comments

kernel test robot March 17, 2023, 1:01 a.m. UTC | #1
Hi Mehdi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on next-20230316]
[cannot apply to linus/master v6.3-rc2]
[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-accelerometer/20230317-075056
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/3ddca10a4c03c3a64afb831cc9dd1e01fe89d305.1679009443.git.mehdi.djait.k%40gmail.com
patch subject: [PATCH 2/3] iio: accel: kionix-kx022a: Add chip_info structure
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20230317/202303170813.jSOLGCL5-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/40c75341c42d0e5bea5d73961202978a4be41cd2
        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-accelerometer/20230317-075056
        git checkout 40c75341c42d0e5bea5d73961202978a4be41cd2
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/iio/

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/202303170813.jSOLGCL5-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/iio/accel/kionix-kx022a.c: In function '__kx022a_fifo_flush':
>> drivers/iio/accel/kionix-kx022a.c:598:9: warning: ISO C90 forbids variable length array 'buffer' [-Wvla]
     598 |         __le16 buffer[data->chip_info->fifo_length * 3];
         |         ^~~~~~
--
   drivers/iio/accel/kionix-kx022a-i2c.c: In function 'kx022a_i2c_probe':
>> drivers/iio/accel/kionix-kx022a-i2c.c:27:19: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
      27 |         chip_info = device_get_match_data(&i2c->dev);
         |                   ^
   drivers/iio/accel/kionix-kx022a-i2c.c:29:27: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
      29 |                 chip_info = (const struct kx022a_chip_info *) id->driver_data;
         |                           ^
--
   drivers/iio/accel/kionix-kx022a-spi.c: In function 'kx022a_spi_probe':
>> drivers/iio/accel/kionix-kx022a-spi.c:27:19: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
      27 |         chip_info = device_get_match_data(&spi->dev);
         |                   ^
   drivers/iio/accel/kionix-kx022a-spi.c:29:27: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
      29 |                 chip_info = (const struct kx022a_chip_info *) id->driver_data;
         |                           ^


vim +/buffer +598 drivers/iio/accel/kionix-kx022a.c

   593	
   594	static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
   595				       bool irq)
   596	{
   597		struct kx022a_data *data = iio_priv(idev);
 > 598		__le16 buffer[data->chip_info->fifo_length * 3];
   599		uint64_t sample_period;
   600		int count, fifo_bytes;
   601		bool renable = false;
   602		int64_t tstamp;
   603		int ret, i;
   604	
   605		fifo_bytes = kx022a_get_fifo_bytes(data);
   606		count = fifo_bytes / KX_FIFO_SAMPLES_SIZE_BYTES;
   607		if (!count)
   608			return 0;
   609	
   610		/*
   611		 * If we are being called from IRQ handler we know the stored timestamp
   612		 * is fairly accurate for the last stored sample. Otherwise, if we are
   613		 * called as a result of a read operation from userspace and hence
   614		 * before the watermark interrupt was triggered, take a timestamp
   615		 * now. We can fall anywhere in between two samples so the error in this
   616		 * case is at most one sample period.
   617		 */
   618		if (!irq) {
   619			/*
   620			 * We need to have the IRQ disabled or we risk of messing-up
   621			 * the timestamps. If we are ran from IRQ, then the
   622			 * IRQF_ONESHOT has us covered - but if we are ran by the
   623			 * user-space read we need to disable the IRQ to be on a safe
   624			 * side. We do this usng synchronous disable so that if the
   625			 * IRQ thread is being ran on other CPU we wait for it to be
   626			 * finished.
   627			 */
   628			disable_irq(data->irq);
   629			renable = true;
   630	
   631			data->old_timestamp = data->timestamp;
   632			data->timestamp = iio_get_time_ns(idev);
   633		}
   634	
   635		/*
   636		 * Approximate timestamps for each of the sample based on the sampling
   637		 * frequency, timestamp for last sample and number of samples.
   638		 *
   639		 * We'd better not use the current bandwidth settings to compute the
   640		 * sample period. The real sample rate varies with the device and
   641		 * small variation adds when we store a large number of samples.
   642		 *
   643		 * To avoid this issue we compute the actual sample period ourselves
   644		 * based on the timestamp delta between the last two flush operations.
   645		 */
   646		if (data->old_timestamp) {
   647			sample_period = data->timestamp - data->old_timestamp;
   648			do_div(sample_period, count);
   649		} else {
   650			sample_period = data->odr_ns;
   651		}
   652		tstamp = data->timestamp - (count - 1) * sample_period;
   653	
   654		if (samples && count > samples) {
   655			/*
   656			 * Here we leave some old samples to the buffer. We need to
   657			 * adjust the timestamp to match the first sample in the buffer
   658			 * or we will miscalculate the sample_period at next round.
   659			 */
   660			data->timestamp -= (count - samples) * sample_period;
   661			count = samples;
   662		}
   663	
   664		fifo_bytes = count * KX_FIFO_SAMPLES_SIZE_BYTES;
   665		ret = regmap_noinc_read(data->regmap, data->chip_info->buf_read,
   666					&buffer[0], fifo_bytes);
   667		if (ret)
   668			goto renable_out;
   669	
   670		for (i = 0; i < count; i++) {
   671			__le16 *sam = &buffer[i * 3];
   672			__le16 *chs;
   673			int bit;
   674	
   675			chs = &data->scan.channels[0];
   676			for_each_set_bit(bit, idev->active_scan_mask, AXIS_MAX)
   677				chs[bit] = sam[bit];
   678	
   679			iio_push_to_buffers_with_timestamp(idev, &data->scan, tstamp);
   680	
   681			tstamp += sample_period;
   682		}
   683	
   684		ret = count;
   685	
   686	renable_out:
   687		if (renable)
   688			enable_irq(data->irq);
   689	
   690		return ret;
   691	}
   692
  
kernel test robot March 17, 2023, 4:57 a.m. UTC | #2
Hi Mehdi,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on jic23-iio/togreg]
[also build test ERROR on next-20230317]
[cannot apply to linus/master v6.3-rc2]
[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-accelerometer/20230317-075056
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/3ddca10a4c03c3a64afb831cc9dd1e01fe89d305.1679009443.git.mehdi.djait.k%40gmail.com
patch subject: [PATCH 2/3] iio: accel: kionix-kx022a: Add chip_info structure
config: i386-randconfig-a011-20230313 (https://download.01.org/0day-ci/archive/20230317/202303171208.uYJzdkrv-lkp@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/40c75341c42d0e5bea5d73961202978a4be41cd2
        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-accelerometer/20230317-075056
        git checkout 40c75341c42d0e5bea5d73961202978a4be41cd2
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 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/202303171208.uYJzdkrv-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

>> drivers/iio/accel/kionix-kx022a-i2c.c:27:12: error: assigning to 'struct kx022a_chip_info *' from 'const void *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
           chip_info = device_get_match_data(&i2c->dev);
                     ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/iio/accel/kionix-kx022a-i2c.c:29:13: error: assigning to 'struct kx022a_chip_info *' from 'const struct kx022a_chip_info *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
                   chip_info = (const struct kx022a_chip_info *) id->driver_data;
                             ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   2 errors generated.
--
>> drivers/iio/accel/kionix-kx022a.c:598:16: warning: variable length array used [-Wvla]
           __le16 buffer[data->chip_info->fifo_length * 3];
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   1 warning generated.
--
>> drivers/iio/accel/kionix-kx022a-spi.c:27:12: error: assigning to 'struct kx022a_chip_info *' from 'const void *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
           chip_info = device_get_match_data(&spi->dev);
                     ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/iio/accel/kionix-kx022a-spi.c:29:13: error: assigning to 'struct kx022a_chip_info *' from 'const struct kx022a_chip_info *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
                   chip_info = (const struct kx022a_chip_info *) id->driver_data;
                             ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   2 errors generated.


vim +27 drivers/iio/accel/kionix-kx022a-i2c.c

    14	
    15	static int kx022a_i2c_probe(struct i2c_client *i2c)
    16	{
    17		struct device *dev = &i2c->dev;
    18		struct kx022a_chip_info *chip_info;
    19		struct regmap *regmap;
    20		const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
    21	
    22		if (!i2c->irq) {
    23			dev_err(dev, "No IRQ configured\n");
    24			return -EINVAL;
    25		}
    26	
  > 27		chip_info = device_get_match_data(&i2c->dev);
    28		if (!chip_info)
  > 29			chip_info = (const struct kx022a_chip_info *) id->driver_data;
    30	
    31		regmap = devm_regmap_init_i2c(i2c, chip_info->regmap_config);
    32		if (IS_ERR(regmap))
    33			return dev_err_probe(dev, PTR_ERR(regmap),
    34					     "Failed to initialize Regmap\n");
    35	
    36		return kx022a_probe_internal(dev, chip_info);
    37	}
    38
  
Andy Shevchenko March 17, 2023, 12:06 p.m. UTC | #3
On Fri, Mar 17, 2023 at 12:48:36AM +0100, Mehdi Djait wrote:
> Refactor the kx022a driver implementation to make it more
> generic and extensible.
> Add the chip_info structure will to the driver's private
> data to hold all the device specific infos.
> Move the enum, struct and constants definitions to the header
> file.

Please, compile and test before sending.

...

>  	.driver = {
> -		.name   = "kx022a-spi",
> +		.name	= "kx022a-spi",
>  		.of_match_table = kx022a_of_match,
>  	},

What was changed here?

...

> -	.id_table = kx022a_id,
> +	.id_table = kx022a_spi_id,

Why do we need this change?

...

> -	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-kx022a",
> +	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-accel",
>  			      dev_name(data->dev));

Shouldn't you use the name from chip info?

...

> +#define KX_MASK_BRES16			    BIT(6)
> +
> +

One blank line is enough.

>  #define KX022A_REG_WHO		0x0f
>  #define KX022A_ID		0xc8
  
Mehdi Djait March 18, 2023, 4:12 p.m. UTC | #4
Hi Andy,

On Fri, Mar 17, 2023 at 02:06:39PM +0200, Andy Shevchenko wrote:
> On Fri, Mar 17, 2023 at 12:48:36AM +0100, Mehdi Djait wrote:
> > Refactor the kx022a driver implementation to make it more
> > generic and extensible.
> > Add the chip_info structure will to the driver's private
> > data to hold all the device specific infos.
> > Move the enum, struct and constants definitions to the header
> > file.
> 
> Please, compile and test before sending.

My bad, I ignored the warnings... 
I will fix it.

> 
> ...
> 
> >  	.driver = {
> > -		.name   = "kx022a-spi",
> > +		.name	= "kx022a-spi",
> >  		.of_match_table = kx022a_of_match,
> >  	},
> 
> What was changed here?

Nothing. I will fix it

> 
> ...
> 
> > -	.id_table = kx022a_id,
> > +	.id_table = kx022a_spi_id,
> 
> Why do we need this change?
> 

For consistency:
i2c: .id_table = kx022a_i2c_id,
spi: .id_table = kx022a_spi_id,

> ...
> 
> > -	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-kx022a",
> > +	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-accel",
> >  			      dev_name(data->dev));
> 
> Shouldn't you use the name from chip info?

I can use the name from chip info. 
dev_name(data->dev) is the original implementation

> 
> ...
> 
> > +#define KX_MASK_BRES16			    BIT(6)
> > +
> > +
> 
> One blank line is enough.

I will change it in v2

--
Kind Regards
Mehdi Djait
  
Jonathan Cameron March 19, 2023, 4:20 p.m. UTC | #5
On Fri, 17 Mar 2023 00:48:36 +0100
Mehdi Djait <mehdi.djait.k@gmail.com> wrote:

> Refactor the kx022a driver implementation to make it more
> generic and extensible.
> Add the chip_info structure will to the driver's private
> data to hold all the device specific infos.
> Move the enum, struct and constants definitions to the header
> file.

You also introduce an i2c_device_id table

Without that I think module autoloading will be broken anyway so that's
definitely a good thing to add.


A few comments inline.  Mostly around reducing the name changes.
Wild cards (or simply shorted 'generic' prefixes like KX_)
almost always bite back in the long run.  Hence we generally just try
to name things after the first device that they were relevant to.

Thanks,

Jonathan

> 
> Signed-off-by: Mehdi Djait <mehdi.djait.k@gmail.com>
> ---
>  drivers/iio/accel/kionix-kx022a-i2c.c |  19 +-
>  drivers/iio/accel/kionix-kx022a-spi.c |  22 +-
>  drivers/iio/accel/kionix-kx022a.c     | 289 ++++++++++++--------------
>  drivers/iio/accel/kionix-kx022a.h     | 128 ++++++++++--
>  4 files changed, 274 insertions(+), 184 deletions(-)
> 
> diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c
> index e6fd02d931b6..21c4c0ae1a68 100644
> --- a/drivers/iio/accel/kionix-kx022a-i2c.c
> +++ b/drivers/iio/accel/kionix-kx022a-i2c.c
> @@ -15,23 +15,35 @@
>  static int kx022a_i2c_probe(struct i2c_client *i2c)
>  {
>  	struct device *dev = &i2c->dev;
> +	struct kx022a_chip_info *chip_info;
>  	struct regmap *regmap;
> +	const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
>  
>  	if (!i2c->irq) {
>  		dev_err(dev, "No IRQ configured\n");
>  		return -EINVAL;
>  	}
>  
> -	regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap);
> +	chip_info = device_get_match_data(&i2c->dev);
> +	if (!chip_info)
> +		chip_info = (const struct kx022a_chip_info *) id->driver_data;

Get id only if the device_get_match_data() fails.

	if (!chip_info) {
		const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
		chip_info = (const struct kx...)
	}	

> +
> +	regmap = devm_regmap_init_i2c(i2c, chip_info->regmap_config);
>  	if (IS_ERR(regmap))
>  		return dev_err_probe(dev, PTR_ERR(regmap),
>  				     "Failed to initialize Regmap\n");
>  
> -	return kx022a_probe_internal(dev);
> +	return kx022a_probe_internal(dev, chip_info);
>  }
>  
> +static const struct i2c_device_id kx022a_i2c_id[] = {
> +	{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx_chip_info[KX022A] },
If there are a small set and we aren't ever going to index the chip_info structure
we might be better off not bothering with the enum and instead using a separate
instance of the structure for each chip.

	.driver_data = (kernel_ulong_t)&kx022a_chip_info, 
etc.

> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
> +
>  static const struct of_device_id kx022a_of_match[] = {
> -	{ .compatible = "kionix,kx022a", },
> +	{ .compatible = "kionix,kx022a", .data = &kx_chip_info[KX022A] },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(of, kx022a_of_match);
> @@ -42,6 +54,7 @@ static struct i2c_driver kx022a_i2c_driver = {
>  		.of_match_table = kx022a_of_match,
>  	  },
>  	.probe_new    = kx022a_i2c_probe,
> +	.id_table     = kx022a_i2c_id,
>  };
>  module_i2c_driver(kx022a_i2c_driver);
>  
> diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c
> index 9cd047f7b346..ec076af0f261 100644
> --- a/drivers/iio/accel/kionix-kx022a-spi.c
> +++ b/drivers/iio/accel/kionix-kx022a-spi.c
> @@ -15,40 +15,46 @@
>  static int kx022a_spi_probe(struct spi_device *spi)
>  {
>  	struct device *dev = &spi->dev;
> +	struct kx022a_chip_info *chip_info;
>  	struct regmap *regmap;
> +	const struct spi_device_id *id = spi_get_device_id(spi);
>  
>  	if (!spi->irq) {
>  		dev_err(dev, "No IRQ configured\n");
>  		return -EINVAL;
>  	}
>  
> -	regmap = devm_regmap_init_spi(spi, &kx022a_regmap);
> +	chip_info = device_get_match_data(&spi->dev);
> +	if (!chip_info)
As above. Get the id only if we are going to use it.

> +		chip_info = (const struct kx022a_chip_info *) id->driver_data;
> +
> +	regmap = devm_regmap_init_spi(spi, chip_info->regmap_config);
>  	if (IS_ERR(regmap))
>  		return dev_err_probe(dev, PTR_ERR(regmap),
>  				     "Failed to initialize Regmap\n");
>  
> -	return kx022a_probe_internal(dev);
> +	return kx022a_probe_internal(dev, chip_info);
>  }
>  
> -static const struct spi_device_id kx022a_id[] = {
> -	{ "kx022a" },
> +static const struct spi_device_id kx022a_spi_id[] = {
> +	{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx_chip_info[KX022A] },
>  	{ }
>  };
> -MODULE_DEVICE_TABLE(spi, kx022a_id);
> +MODULE_DEVICE_TABLE(spi, kx022a_spi_id);
>  
>  static const struct of_device_id kx022a_of_match[] = {
> -	{ .compatible = "kionix,kx022a", },
> +	{ .compatible = "kionix,kx022a", .data = &kx_chip_info[KX022A] },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(of, kx022a_of_match);
>  
>  static struct spi_driver kx022a_spi_driver = {
>  	.driver = {
> -		.name   = "kx022a-spi",
> +		.name	= "kx022a-spi",
>  		.of_match_table = kx022a_of_match,
>  	},
>  	.probe = kx022a_spi_probe,
> -	.id_table = kx022a_id,
> +	.id_table = kx022a_spi_id,
>  };
>  module_spi_driver(kx022a_spi_driver);
>  
> diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c
> index 8dac0337c249..27e8642aa8f5 100644
> --- a/drivers/iio/accel/kionix-kx022a.c
> +++ b/drivers/iio/accel/kionix-kx022a.c
> @@ -26,29 +26,7 @@
..

> -#define KX022A_ACCEL_CHAN(axis, index)				\
> +#define KX022A_ACCEL_CHAN(axis, index, device)			\
>  {								\
>  	.type = IIO_ACCEL,					\
>  	.modified = 1,						\
> @@ -220,7 +158,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
>  				BIT(IIO_CHAN_INFO_SCALE) |	\
>  				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
>  	.ext_info = kx022a_ext_info,				\
> -	.address = KX022A_REG_##axis##OUT_L,			\
> +	.address = device##_REG_##axis##OUT_L,			\

I'm not particularly keen on this because it is hard to search for.
It wasn't great before, but it's getting worse.

Perhaps just put the fully defined address in as a parameter to the macro.

>  	.scan_index = index,					\
>  	.scan_type = {                                          \
>  		.sign = 's',					\
> @@ -231,9 +169,9 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
>  }
>  
>  static const struct iio_chan_spec kx022a_channels[] = {
> -	KX022A_ACCEL_CHAN(X, 0),
> -	KX022A_ACCEL_CHAN(Y, 1),
> -	KX022A_ACCEL_CHAN(Z, 2),
> +	KX022A_ACCEL_CHAN(X, 0, KX022A),
> +	KX022A_ACCEL_CHAN(Y, 1, KX022A),
> +	KX022A_ACCEL_CHAN(Z, 2, KX022A),
>  	IIO_CHAN_SOFT_TIMESTAMP(3),
>  };
>  
> @@ -286,6 +224,34 @@ static const int kx022a_scale_table[][2] = {
>  	{ 4788, 403320 },
>  };
>  
> +const struct kx022a_chip_info kx_chip_info[] = {
> +	[KX022A] = {
> +		.name		  = "kx022a",
> +		.type		  = KX022A,
> +		.regmap_config	  = &kx022a_regmap_config,
> +		.channels	  = kx022a_channels,
> +		.num_channels	  = ARRAY_SIZE(kx022a_channels),
> +		.fifo_length	  = KX022A_FIFO_LENGTH,
> +		.who		  = KX022A_REG_WHO,
> +		.id		  = KX022A_ID,
> +		.cntl		  = KX022A_REG_CNTL,
> +		.cntl2		  = KX022A_REG_CNTL2,
> +		.odcntl		  = KX022A_REG_ODCNTL,
> +		.buf_cntl1	  = KX022A_REG_BUF_CNTL1,
> +		.buf_cntl2	  = KX022A_REG_BUF_CNTL2,
> +		.buf_clear	  = KX022A_REG_BUF_CLEAR,
> +		.buf_status1	  = KX022A_REG_BUF_STATUS_1,
> +		.buf_smp_lvl_mask = KX022A_MASK_BUF_SMP_LVL,
> +		.buf_read	  = KX022A_REG_BUF_READ,
> +		.inc1		  = KX022A_REG_INC1,
> +		.inc4		  = KX022A_REG_INC4,
> +		.inc5		  = KX022A_REG_INC5,
> +		.inc6		  = KX022A_REG_INC6,
> +		.xout_l		  = KX022A_REG_XOUT_L,
> +	},
> +};
> +EXPORT_SYMBOL_NS_GPL(kx_chip_info, IIO_KX022A);

...

>  
> +static int kx022a_get_fifo_bytes(struct kx022a_data *data)

Factoring this out looks like an unrelated change.  Fine to do it but should be a
separate patch.

If you need a device type specific version of this add a function pointer
to your chip_info structure.  Given you don't add one for the next patch
I think this is just refactoring and so fine to do, but needs to be in a separate
patch from this one with a description that says why you are doing it.

> +{
> +	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);
> +
> +	/*
> +	 * The KX022A has FIFO which can store 43 samples of HiRes data from 2
> +	 * channels. This equals to 43 (samples) * 3 (channels) * 2 (bytes/sample) to
> +	 * 258 bytes of sample data. The quirk to know is that the amount of bytes in
> +	 * the FIFO is advertised via 8 bit register (max value 255). The thing to note
> +	 * is that full 258 bytes of data is indicated using the max value 255.
> +	 */
> +	if (data->chip_info->type == KX022A && fifo_bytes == KX022A_FIFO_FULL_VALUE)
> +		fifo_bytes = KX022A_FIFO_MAX_BYTES;
> +
> +	if (fifo_bytes % KX_FIFO_SAMPLES_SIZE_BYTES)
> +		dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
> +
> +	return fifo_bytes;
> +}
> +
>  static int kx022a_drop_fifo_contents(struct kx022a_data *data)
>  {
>  	/*
> @@ -593,35 +588,22 @@ static int kx022a_drop_fifo_contents(struct kx022a_data *data)
>  	 */
>  	data->timestamp = 0;
>  
> -	return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0);
> +	return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0);
>  }
>  
>  static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
>  			       bool irq)
>  {
>  	struct kx022a_data *data = iio_priv(idev);
> -	struct device *dev = regmap_get_device(data->regmap);
> -	__le16 buffer[KX022A_FIFO_LENGTH * 3];
> +	__le16 buffer[data->chip_info->fifo_length * 3];
>  	uint64_t sample_period;
>  	int count, fifo_bytes;
>  	bool renable = false;
>  	int64_t tstamp;
>  	int ret, i;
>  
> -	ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes);
> -	if (ret) {
> -		dev_err(dev, "Error reading buffer status\n");
> -		return ret;
> -	}
> -
> -	/* Let's not overflow if we for some reason get bogus value from i2c */
> -	if (fifo_bytes == KX022A_FIFO_FULL_VALUE)
> -		fifo_bytes = KX022A_FIFO_MAX_BYTES;
> -
> -	if (fifo_bytes % KX022A_FIFO_SAMPLES_SIZE_BYTES)
> -		dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
> -
> -	count = fifo_bytes / KX022A_FIFO_SAMPLES_SIZE_BYTES;
> +	fifo_bytes = kx022a_get_fifo_bytes(data);
> +	count = fifo_bytes / KX_FIFO_SAMPLES_SIZE_BYTES;
>  	if (!count)
>  		return 0;
...

>  
> @@ -969,25 +949,25 @@ static int kx022a_chip_init(struct kx022a_data *data)
>  	 */
>  	msleep(1);
>  
> -	ret = regmap_read_poll_timeout(data->regmap, KX022A_REG_CNTL2, val,
> -				       !(val & KX022A_MASK_SRST),
> -				       KX022A_SOFT_RESET_WAIT_TIME_US,
> -				       KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US);
> +	ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val,
> +				       !(val & KX_MASK_SRST),
> +				       KX_SOFT_RESET_WAIT_TIME_US,
> +				       KX_SOFT_RESET_TOTAL_WAIT_TIME_US);

Where ever there are lots of accesses to data->chip_info I'd add
a local chip_info variable to improve readabilty a bit. Might be
worth doing the same with regmap (in a different patch)

>  	if (ret) {
>  		dev_err(data->dev, "Sensor reset %s\n",
> -			val & KX022A_MASK_SRST ? "timeout" : "fail#");
> +			val & KX_MASK_SRST ? "timeout" : "fail#");
>  		return ret;
>  	}
>  
> -	ret = regmap_reinit_cache(data->regmap, &kx022a_regmap);
> +	ret = regmap_reinit_cache(data->regmap, data->chip_info->regmap_config);
>  	if (ret) {
>  		dev_err(data->dev, "Failed to reinit reg cache\n");
>  		return ret;
>  	}
>  
>  	/* set data res 16bit */
> -	ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
> -			      KX022A_MASK_BRES16);
> +	ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
> +			      KX_MASK_BRES16);
>  	if (ret) {
>  		dev_err(data->dev, "Failed to set data resolution\n");
>  		return ret;
> @@ -996,7 +976,7 @@ static int kx022a_chip_init(struct kx022a_data *data)
>  	return kx022a_prepare_irq_pin(data);
>  }
>  
> -int kx022a_probe_internal(struct device *dev)
> +int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)
>  {
>  	static const char * const regulator_names[] = {"io-vdd", "vdd"};
>  	struct iio_trigger *indio_trig;
> @@ -1023,6 +1003,7 @@ int kx022a_probe_internal(struct device *dev)
>  		return -ENOMEM;
>  
>  	data = iio_priv(idev);
> +	data->chip_info = chip_info;
>  
>  	/*
>  	 * VDD is the analog and digital domain voltage supply and
> @@ -1033,37 +1014,37 @@ int kx022a_probe_internal(struct device *dev)
>  	if (ret && ret != -ENODEV)
>  		return dev_err_probe(dev, ret, "failed to enable regulator\n");
>  
> -	ret = regmap_read(regmap, KX022A_REG_WHO, &chip_id);
> +	ret = regmap_read(regmap, data->chip_info->who, &chip_id);

I think  you have chip_info available as a local variable.
Use that in this function to shorten lines with no loss of readability.

>  	if (ret)
>  		return dev_err_probe(dev, ret, "Failed to access sensor\n");
>  
> -	if (chip_id != KX022A_ID) {
> +	if (chip_id != data->chip_info->id) {

Recently we've tried to avoid introduce error returns on a failure to match
and instead just warn and go ahead with assumption that we have a correct
dt-binding telling us that some new device with a different ID is backwards
compatible with the old one.  Obviously not part of this patch though but
something to think about later (if you don't do it later in this series).

>  		dev_err(dev, "unsupported device 0x%x\n", chip_id);
>  		return -EINVAL;
>  	}

...


>  
>  	data->regmap = regmap;
>  	data->dev = dev;
>  	data->irq = irq;
> -	data->odr_ns = KX022A_DEFAULT_PERIOD_NS;
> +	data->odr_ns = KX_DEFAULT_PERIOD_NS;
>  	mutex_init(&data->mutex);
>  
> -	idev->channels = kx022a_channels;
> -	idev->num_channels = ARRAY_SIZE(kx022a_channels);
> -	idev->name = "kx022-accel";

Ah. Missed this naming in original driver review.  We only normally
postfix with accel in devices that have multiple sensors with separate
drivers. Don't think that is true of the kx022a.
It's ABI so we are stuck with it, but avoid repeating that issue
for new devices.

> +	idev->channels = data->chip_info->channels;
> +	idev->num_channels = data->chip_info->num_channels;
> +	idev->name = data->chip_info->name;
>  	idev->info = &kx022a_info;
>  	idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
>  	idev->available_scan_masks = kx022a_scan_masks;
> @@ -1112,7 +1093,7 @@ int kx022a_probe_internal(struct device *dev)
>  	 * No need to check for NULL. request_threaded_irq() defaults to
>  	 * dev_name() should the alloc fail.
>  	 */
> -	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-kx022a",
> +	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-accel",
>  			      dev_name(data->dev));

Why name change here?  It's not particularly important but if we can avoid
it that would be a nice to have.

>  
>  	ret = devm_request_threaded_irq(data->dev, irq, kx022a_irq_handler,
> diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h
> index 12424649d438..3bb40e9f5613 100644
> --- a/drivers/iio/accel/kionix-kx022a.h
> +++ b/drivers/iio/accel/kionix-kx022a.h
> @@ -11,24 +11,48 @@
>  #include <linux/bits.h>
>  #include <linux/regmap.h>
>  
> +#include <linux/iio/iio.h>
> +
> +/* Common for all supported devices */
> +#define KX_FIFO_SAMPLES_SIZE_BYTES	    6
Even if they are used across multiple parts, don't rename them to
be generic.  It almost always causes churn / name clashes etc.

It is absolutely fine to have driver specific naming that is based
on the first supported part rather than trying to make it cover them
all.

> +#define KX_SOFT_RESET_WAIT_TIME_US	    (5 * USEC_PER_MSEC)
> +#define KX_SOFT_RESET_TOTAL_WAIT_TIME_US    (500 * USEC_PER_MSEC)
> +#define KX_DEFAULT_PERIOD_NS		    (20 * NSEC_PER_MSEC)
> +#define KX_MASK_GSEL			    GENMASK(4, 3)
> +#define KX_MASK_ODR			    GENMASK(3, 0)
> +#define KX_MASK_WM_TH			    GENMASK(6, 0)
> +#define KX_GSEL_SHIFT			    3
> +#define KX_MASK_IEN			    BIT(5)
> +#define KX_MASK_DRDY			    BIT(5)
> +#define KX_MASK_PC1			    BIT(7)
> +#define KX_MASK_IPOL			    BIT(4)
> +#define KX_IPOL_LOW			    0
> +#define KX_MASK_ITYP			    BIT(3)
> +#define KX_ITYP_LEVEL			    0
> +#define KX_MASK_INS2_DRDY		    BIT(4)
> +#define KX_MASK_WMI			    BIT(5)
> +#define KX_MASK_BUF_EN			    BIT(7)
> +#define KX_MASK_SRST			    BIT(7)
> +#define KX_MASK_BRES16			    BIT(6)
> +
> +
>  #define KX022A_REG_WHO		0x0f
>  #define KX022A_ID		0xc8
>  
> +#define KX022A_FIFO_LENGTH	43
> +#define KX022A_FIFO_FULL_VALUE	255
> +#define KX022A_FIFO_MAX_BYTES					\
> +	 (KX022A_FIFO_LENGTH * KX_FIFO_SAMPLES_SIZE_BYTES)
> +
>  #define KX022A_REG_CNTL2	0x19
> -#define KX022A_MASK_SRST	BIT(7)
>  #define KX022A_REG_CNTL		0x18
> -#define KX022A_MASK_PC1		BIT(7)
>  #define KX022A_MASK_RES		BIT(6)
> -#define KX022A_MASK_DRDY	BIT(5)
> -#define KX022A_MASK_GSEL	GENMASK(4, 3)
> -#define KX022A_GSEL_SHIFT	3
>  #define KX022A_GSEL_2		0x0
>  #define KX022A_GSEL_4		BIT(3)
>  #define KX022A_GSEL_8		BIT(4)
>  #define KX022A_GSEL_16		GENMASK(4, 3)
>  
>  #define KX022A_REG_INS2		0x13
> -#define KX022A_MASK_INS2_DRDY	BIT(4)
>  #define KX122_MASK_INS2_WMI	BIT(5)
>  
>  #define KX022A_REG_XHP_L	0x0
> @@ -45,38 +69,104 @@
>  #define KX022A_REG_MAN_WAKE	0x2c
>  
>  #define KX022A_REG_BUF_CNTL1	0x3a
> -#define KX022A_MASK_WM_TH	GENMASK(6, 0)
>  #define KX022A_REG_BUF_CNTL2	0x3b
> -#define KX022A_MASK_BUF_EN	BIT(7)
> -#define KX022A_MASK_BRES16	BIT(6)
>  #define KX022A_REG_BUF_STATUS_1	0x3c
>  #define KX022A_REG_BUF_STATUS_2	0x3d
> +#define KX022A_MASK_BUF_SMP_LVL GENMASK(6, 0)
>  #define KX022A_REG_BUF_CLEAR	0x3e
>  #define KX022A_REG_BUF_READ	0x3f
> -#define KX022A_MASK_ODR		GENMASK(3, 0)
>  #define KX022A_ODR_SHIFT	3
>  #define KX022A_FIFO_MAX_WMI_TH	41
>  
>  #define KX022A_REG_INC1		0x1c
>  #define KX022A_REG_INC5		0x20
>  #define KX022A_REG_INC6		0x21
> -#define KX022A_MASK_IEN		BIT(5)
> -#define KX022A_MASK_IPOL	BIT(4)
>  #define KX022A_IPOL_LOW		0
> -#define KX022A_IPOL_HIGH	KX022A_MASK_IPOL1
> -#define KX022A_MASK_ITYP	BIT(3)
> -#define KX022A_ITYP_PULSE	KX022A_MASK_ITYP
> -#define KX022A_ITYP_LEVEL	0
> +#define KX022A_IPOL_HIGH	KX_MASK_IPOL
> +#define KX022A_ITYP_PULSE	KX_MASK_ITYP
>  
>  #define KX022A_REG_INC4		0x1f
> -#define KX022A_MASK_WMI		BIT(5)
>  
>  #define KX022A_REG_SELF_TEST	0x60
>  #define KX022A_MAX_REGISTER	0x60
>  
> +enum kx022a_device_type {
> +	KX022A,
> +};

As below. I'd avoid using the enum unless needed.
That can make sense where a driver supports lots of devices but I don't think
it does here.

> +
> +enum {
> +	KX_STATE_SAMPLE,
> +	KX_STATE_FIFO,
> +};
> +
> +enum {
> +	AXIS_X,
> +	AXIS_Y,
> +	AXIS_Z,
> +	AXIS_MAX
> +};
> +
>  struct device;
>  
> -int kx022a_probe_internal(struct device *dev);
> -extern const struct regmap_config kx022a_regmap;
> +struct kx022a_chip_info {
> +	const char *name;
> +	enum kx022a_device_type type;
> +	const struct regmap_config *regmap_config;
> +	const struct iio_chan_spec *channels;
> +	unsigned int num_channels;
> +	unsigned int fifo_length;
> +	u8 who;
Some of these are no immediately obvious so either rename the
field so it is more obvious what it is, or add comments.

> +	u8 id;
> +	u8 cntl;
> +	u8 cntl2;
> +	u8 odcntl;
> +	u8 buf_cntl1;
> +	u8 buf_cntl2;
> +	u8 buf_clear;
> +	u8 buf_status1;
> +	u16 buf_smp_lvl_mask;
> +	u8 buf_read;
> +	u8 inc1;
> +	u8 inc4;
> +	u8 inc5;
> +	u8 inc6;
> +	u8 xout_l;
> +};
> +
> +struct kx022a_data {

Why move this to the header?  Unless there is a strong reason
I'd prefer this to stay down in the .c file.


> +	const struct kx022a_chip_info *chip_info;
> +	struct regmap *regmap;
> +	struct iio_trigger *trig;
> +	struct device *dev;
> +	struct iio_mount_matrix orientation;
> +	int64_t timestamp, old_timestamp;
> +
> +	int irq;
> +	int inc_reg;
> +	int ien_reg;
> +
> +	unsigned int state;
> +	unsigned int odr_ns;
> +
> +	bool trigger_enabled;
> +	/*
> +	 * Prevent toggling the sensor stby/active state (PC1 bit) in the
> +	 * middle of a configuration, or when the fifo is enabled. Also,
> +	 * protect the data stored/retrieved from this structure from
> +	 * concurrent accesses.
> +	 */
> +	struct mutex mutex;
> +	u8 watermark;
> +
> +	/* 3 x 16bit accel data + timestamp */
> +	__le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
> +	struct {
> +		__le16 channels[3];
> +		s64 ts __aligned(8);
> +	} scan;
> +};
> +
> +int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info);
> +extern const struct kx022a_chip_info kx_chip_info[];
As mentioned in the bus specific driver, given there is a small set and we need the enum
just to index this, I'd just have one per supported device.

extern const struct kx022a_chip_info kx022a_chip_info;
extern const struct kx022a_chip_info kx321_chip_info;

etc


>  
>  #endif
  
Matti Vaittinen March 20, 2023, 7:17 a.m. UTC | #6
Hi Mehdi and Jonathan,

Just my take on couple of comments from Jonathan :) I still have my own 
review to do though...

On 3/19/23 18:20, Jonathan Cameron wrote:
> On Fri, 17 Mar 2023 00:48:36 +0100
> Mehdi Djait <mehdi.djait.k@gmail.com> wrote:
> 
>> Refactor the kx022a driver implementation to make it more
>> generic and extensible.
>> Add the chip_info structure will to the driver's private
>> data to hold all the device specific infos.
>> Move the enum, struct and constants definitions to the header
>> file.
> 
> You also introduce an i2c_device_id table
> 
> Without that I think module autoloading will be broken anyway so that's
> definitely a good thing to add.

I am pretty sure the autoloading worked for OF-systems. But yes, adding 
the i2c_device_id is probably a good idea. Thanks.

> A few comments inline.  Mostly around reducing the name changes.
> Wild cards (or simply shorted 'generic' prefixes like KX_)
> almost always bite back in the long run.  Hence we generally just try
> to name things after the first device that they were relevant to.

I must say I disagree on this with you Jonathan. I know wildcards tend 
to get confusing - but I still like the idea of showing which of the 
definitions are IC specific and which ones are generic or at least used 
by more than one variant - especially as long as we only have two 
supported ICs. I definitely like the macro naming added by Mehdi. This 
approach has been very helpful for me for example in the BD718x7 
(BD71837/BD71847/BD71850) PMIC driver. My take on this is:

1) I like the generic KX_define.
2) I would not try adding wildcards like KX_X22 - to denote support for 
122 and 022 - while not supporting 132 - in my experience - that won't 
scale.
3) I definitely like the idea of using exact model number prefix for 
'stuff' which is intended to work only on one exact model.

Regarding the 3) - I am not so strict on how the register/mask defines 
are handled - I _like_ the 1) 2) 3) approach above - but mask/register 
defines tend to get set (correctly) once and not required to be looked 
up after this. But. When the 'stuff' is functions - this gets very 
useful as one is very often required to see which functions are executed 
on which IC variant. Same goes to structs.

So, if we manage to convince Jonathan about the naming, then I like what 
yoo had here! I would hovever do it in two steps. I would at first do 
renaming patch where the generic defines were renamed - without any 
functional changes - and only then add the kx132 stuff in a subsequent 
patch. That would simplify seeing which changes are just renaming and 
which are functional ones.

But here, I must go with the wind - if subsystem maintainer says the 
code should not have naming like this - then I have no say over it... :/

>>   
>> +static const struct i2c_device_id kx022a_i2c_id[] = {
>> +	{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx_chip_info[KX022A] },
> If there are a small set and we aren't ever going to index the chip_info structure
> we might be better off not bothering with the enum and instead using a separate
> instance of the structure for each chip.
> 

I kind of like also the table added by Mehdi. I admit I was at first 
just thinking that we should have a pointer to the struct here without 
any tables - but... After I took a peek in the kionix-kx022a.c - I kind 
of liked the table and not exporting the struct names. So, I don't have 
a strong opinion on this.

I think it's worth noting that this driver could (maybe easily enough) 
be extended to support also a few other kionix accelerometers. Maybe, if 
we don't scare Mehdi away, we will see a few other variants supported as 
well ;)

>>   	data->regmap = regmap;
>>   	data->dev = dev;
>>   	data->irq = irq;
>> -	data->odr_ns = KX022A_DEFAULT_PERIOD_NS;
>> +	data->odr_ns = KX_DEFAULT_PERIOD_NS;
>>   	mutex_init(&data->mutex);
>>   
>> -	idev->channels = kx022a_channels;
>> -	idev->num_channels = ARRAY_SIZE(kx022a_channels);
>> -	idev->name = "kx022-accel";
> 
> Ah. Missed this naming in original driver review.  We only normally
> postfix with accel in devices that have multiple sensors with separate
> drivers. Don't think that is true of the kx022a.

Ouch. I am not 100% sure but may be you didn't miss it. It may be I just 
missed fixing this because your comment here sounds somewhat familiar to 
me! (Or then you commented on suffix in driver-name).

> It's ABI so we are stuck with it, but avoid repeating that issue
> for new devices. >

>>   
>> +enum kx022a_device_type {
>> +	KX022A,
>> +};
> 
> As below. I'd avoid using the enum unless needed.
> That can make sense where a driver supports lots of devices but I don't think
> it does here.

Well, I know it is usually not too clever to be prepared for the future 
stuff too well. But - I don't think the enum and table are adding much 
of complexity? I am saying this as I think this driver could be extended 
to support also kx022 (without the A), kx023, kx122. I've also seen some 
references to model kx022A-120B (but I have no idea what's the story 
there or if that IC is publicly available). Maybe Mehdi would like to 
extend this driver further after the KX132 is done ;)

>> -int kx022a_probe_internal(struct device *dev);
>> -extern const struct regmap_config kx022a_regmap;
>> +struct kx022a_chip_info {
>> +	const char *name;
>> +	enum kx022a_device_type type;
>> +	const struct regmap_config *regmap_config;
>> +	const struct iio_chan_spec *channels;
>> +	unsigned int num_channels;
>> +	unsigned int fifo_length;
>> +	u8 who;
> Some of these are no immediately obvious so either rename the
> field so it is more obvious what it is, or add comments.

I would vote for adding a comment :) I like the who. Both the band and 
this member here :) Data-sheet has register named as "who_am_i" - so I 
don't think this name is too obfuscating - and what matters to me - it 
is short yet meaningful.

>> +	u8 id;
>> +	u8 cntl;
>> +	u8 cntl2;
>> +	u8 odcntl;
>> +	u8 buf_cntl1;
>> +	u8 buf_cntl2;
>> +	u8 buf_clear;
>> +	u8 buf_status1;
>> +	u16 buf_smp_lvl_mask;
>> +	u8 buf_read;
>> +	u8 inc1;
>> +	u8 inc4;
>> +	u8 inc5;
>> +	u8 inc6;
>> +	u8 xout_l;
>> +};
>> +
>> +struct kx022a_data {
> 
> Why move this to the header?  Unless there is a strong reason
> I'd prefer this to stay down in the .c file.

So would I. It's definitely nice to be able to see the struct in the 
same file where the code referencing it is.


Yours,
	-- Matti
  
Matti Vaittinen March 20, 2023, 9:35 a.m. UTC | #7
On 3/17/23 01:48, Mehdi Djait wrote:
> Refactor the kx022a driver implementation to make it more
> generic and extensible.
> Add the chip_info structure will to the driver's private
> data to hold all the device specific infos.
> Move the enum, struct and constants definitions to the header
> file.
> 
> Signed-off-by: Mehdi Djait <mehdi.djait.k@gmail.com>
> ---
>   drivers/iio/accel/kionix-kx022a-i2c.c |  19 +-
>   drivers/iio/accel/kionix-kx022a-spi.c |  22 +-
>   drivers/iio/accel/kionix-kx022a.c     | 289 ++++++++++++--------------
>   drivers/iio/accel/kionix-kx022a.h     | 128 ++++++++++--
>   4 files changed, 274 insertions(+), 184 deletions(-)
> 
> diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c
> index e6fd02d931b6..21c4c0ae1a68 100644
> --- a/drivers/iio/accel/kionix-kx022a-i2c.c
> +++ b/drivers/iio/accel/kionix-kx022a-i2c.c
> @@ -15,23 +15,35 @@
>   static int kx022a_i2c_probe(struct i2c_client *i2c)
>   {
>   	struct device *dev = &i2c->dev;
> +	struct kx022a_chip_info *chip_info;
>   	struct regmap *regmap;
> +	const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
>   
>   	if (!i2c->irq) {
>   		dev_err(dev, "No IRQ configured\n");
>   		return -EINVAL;
>   	}
>   
> -	regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap);
> +	chip_info = device_get_match_data(&i2c->dev);
> +	if (!chip_info)
> +		chip_info = (const struct kx022a_chip_info *) id->driver_data;
> +
> +	regmap = devm_regmap_init_i2c(i2c, chip_info->regmap_config);
>   	if (IS_ERR(regmap))
>   		return dev_err_probe(dev, PTR_ERR(regmap),
>   				     "Failed to initialize Regmap\n");

Hm. I would like to pull the regmap_config out of the chip_info struct. 
As far as I see, the regmap_config is only needed in these bus specific 
files. On the other hand, the chip-info is only needed in the 
kionix-kx022a.c file, right?

So, maybe you could here just get the regmap_config based on the chip-id 
(enum value you added - the data pointer in match tables could be just 
the enum value indicating the IC type). Then, you could pass this enum 
value to kx022a_probe_internal() - and the chip-info struct could be 
selected in the kionix-kx022a.c based on it. That way you would not need 
the struct chip-info here or regmap_config in kionix-kx022a.c. Same in 
the *-spi.c

Something like:

enum {
	KIONIX_IC_KX022A,
	KIONIX_IC_KX132_xxx, /* xxx denotes accurate model suffix */
};
	
static const struct of_device_id kx022a_of_match[] = {
	{ .compatible = "kionix,kx022a", .data = KIONIX_IC_KX022A },
	...

chip_id = device_get_match_data(&i2c->dev);

regmap_cfg = kx022a_kx_regmap_cfg[chip_id];
regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
...
return kx022a_probe_internal(dev, chip_id);

Do you think that would work?

OTOH, to really benefit from this we should probably pull out the 
regmap-configs from the kionix-kx022a.c. I am not really sure where we 
should put it then though. Hence, if there is no good ideas how to split 
the config and chip-info so they are only available/used where needed - 
then I am also Ok with the current approach.

> -
> -struct kx022a_data {
> -	struct regmap *regmap;
> -	struct iio_trigger *trig;
> -	struct device *dev;
> -	struct iio_mount_matrix orientation;
> -	int64_t timestamp, old_timestamp;
> -
> -	int irq;
> -	int inc_reg;
> -	int ien_reg;
> -
> -	unsigned int state;
> -	unsigned int odr_ns;
> -
> -	bool trigger_enabled;
> -	/*
> -	 * Prevent toggling the sensor stby/active state (PC1 bit) in the
> -	 * middle of a configuration, or when the fifo is enabled. Also,
> -	 * protect the data stored/retrieved from this structure from
> -	 * concurrent accesses.
> -	 */
> -	struct mutex mutex;
> -	u8 watermark;
> -
> -	/* 3 x 16bit accel data + timestamp */
> -	__le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
> -	struct {
> -		__le16 channels[3];
> -		s64 ts __aligned(8);
> -	} scan;
> -};

As mentioned by Jonathan - It'd be better to keep this struct in C-file.

>   
> +const struct kx022a_chip_info kx_chip_info[] = {
> +	[KX022A] = {
> +		.name		  = "kx022a",
> +		.type		  = KX022A,
> +		.regmap_config	  = &kx022a_regmap_config,

As mentioned above, the regmap config is not really needed after the 
regmap is initialized. Id prefer this not being part of the chip info.

> +		.channels	  = kx022a_channels,
> +		.num_channels	  = ARRAY_SIZE(kx022a_channels),
> +		.fifo_length	  = KX022A_FIFO_LENGTH,
> +		.who		  = KX022A_REG_WHO,
> +		.id		  = KX022A_ID,
> +		.cntl		  = KX022A_REG_CNTL,
> +		.cntl2		  = KX022A_REG_CNTL2,
> +		.odcntl		  = KX022A_REG_ODCNTL,
> +		.buf_cntl1	  = KX022A_REG_BUF_CNTL1,
> +		.buf_cntl2	  = KX022A_REG_BUF_CNTL2,
> +		.buf_clear	  = KX022A_REG_BUF_CLEAR,
> +		.buf_status1	  = KX022A_REG_BUF_STATUS_1,
> +		.buf_smp_lvl_mask = KX022A_MASK_BUF_SMP_LVL,
> +		.buf_read	  = KX022A_REG_BUF_READ,
> +		.inc1		  = KX022A_REG_INC1,
> +		.inc4		  = KX022A_REG_INC4,
> +		.inc5		  = KX022A_REG_INC5,
> +		.inc6		  = KX022A_REG_INC6,
> +		.xout_l		  = KX022A_REG_XOUT_L,
> +	},
> +};
> +EXPORT_SYMBOL_NS_GPL(kx_chip_info, IIO_KX022A);
> +
>   static int kx022a_read_avail(struct iio_dev *indio_dev,
>   			     struct iio_chan_spec const *chan,
>   			     const int **vals, int *type, int *length,
> @@ -309,19 +275,17 @@ static int kx022a_read_avail(struct iio_dev *indio_dev,
>   	}
>   }
>   
> -#define KX022A_DEFAULT_PERIOD_NS (20 * NSEC_PER_MSEC)
> -
>   static void kx022a_reg2freq(unsigned int val,  int *val1, int *val2)
>   {
> -	*val1 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][0];
> -	*val2 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][1];
> +	*val1 = kx022a_accel_samp_freq_table[val & KX_MASK_ODR][0];
> +	*val2 = kx022a_accel_samp_freq_table[val & KX_MASK_ODR][1];
>   }
>   

As mentioned elsewhere, doing the renaming separately from the 
functional changes will ease the reviewing.


>   
> +static int kx022a_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);
> +
> +	/*
> +	 * The KX022A has FIFO which can store 43 samples of HiRes data from 2
> +	 * channels. This equals to 43 (samples) * 3 (channels) * 2 (bytes/sample) to
> +	 * 258 bytes of sample data. The quirk to know is that the amount of bytes in
> +	 * the FIFO is advertised via 8 bit register (max value 255). The thing to note
> +	 * is that full 258 bytes of data is indicated using the max value 255.
> +	 */
> +	if (data->chip_info->type == KX022A && fifo_bytes == KX022A_FIFO_FULL_VALUE)
> +		fifo_bytes = KX022A_FIFO_MAX_BYTES;
> +
> +	if (fifo_bytes % KX_FIFO_SAMPLES_SIZE_BYTES)
> +		dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
> +
> +	return fifo_bytes;
> +}

I like adding this function. Here I agree with Jonathan - having a 
device specific functions would clarify this a bit. The KX022A "quirk" 
is a bit confusing. You could then get rid of the buf_smp_lvl_mask.

> +
>   static int kx022a_drop_fifo_contents(struct kx022a_data *data)
>   {
>   	/*
> @@ -593,35 +588,22 @@ static int kx022a_drop_fifo_contents(struct kx022a_data *data)
>   	 */
>   	data->timestamp = 0;
>   
> -	return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0);
> +	return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0);
>   }
>   
>   static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
>   			       bool irq)
>   {
>   	struct kx022a_data *data = iio_priv(idev);
> -	struct device *dev = regmap_get_device(data->regmap);
> -	__le16 buffer[KX022A_FIFO_LENGTH * 3];
> +	__le16 buffer[data->chip_info->fifo_length * 3];

I don't like this. Having the length of an array decided at run-time is 
not something I appreciate. Maybe you could just always reserve the 
memory so that the largest FIFO gets supported. I am just wondering how 
large arrays we can safely allocate from the stack?


> @@ -812,14 +792,14 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
>   		goto unlock_out;
>   
>   	/* Enable buffer */
> -	ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
> -			      KX022A_MASK_BUF_EN);
> +	ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
> +			      KX_MASK_BUF_EN);
>   	if (ret)
>   		goto unlock_out;
>   
> -	data->state |= KX022A_STATE_FIFO;
> +	data->state |= KX_STATE_FIFO;
>   	ret = regmap_set_bits(data->regmap, data->ien_reg,
> -			      KX022A_MASK_WMI);
> +			      KX_MASK_WMI);

I think this fits to one line now. (even on my screen)

>   	if (ret)
>   		goto unlock_out;
>   

> -int kx022a_probe_internal(struct device *dev)
> +int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)

As mentioned elsewhere, this might also work if the chip-type enum was 
passed here as parameter. That way the bus specific part would not need 
to know about the struct chip_info...

>   {
>   	static const char * const regulator_names[] = {"io-vdd", "vdd"};
>   	struct iio_trigger *indio_trig;
> @@ -1023,6 +1003,7 @@ int kx022a_probe_internal(struct device *dev)
>   		return -ENOMEM;
>   
>   	data = iio_priv(idev);
> +	data->chip_info = chip_info;

...Here you could then pick the correct chip_info based on the chip-type 
enum. In that case I'd like to get the regmap_config(s) in own file. Not 
sure how that would look like though.

All in all, I like how this looks like. Nice job!

Yours,
	-- Matti
  
Andy Shevchenko March 20, 2023, 12:02 p.m. UTC | #8
On Mon, Mar 20, 2023 at 11:35:06AM +0200, Matti Vaittinen wrote:
> On 3/17/23 01:48, Mehdi Djait wrote:
> > Refactor the kx022a driver implementation to make it more
> > generic and extensible.
> > Add the chip_info structure will to the driver's private
> > data to hold all the device specific infos.
> > Move the enum, struct and constants definitions to the header
> > file.

...

> Something like:
> 
> enum {
> 	KIONIX_IC_KX022A,
> 	KIONIX_IC_KX132_xxx, /* xxx denotes accurate model suffix */
> };
> 	
> static const struct of_device_id kx022a_of_match[] = {
> 	{ .compatible = "kionix,kx022a", .data = KIONIX_IC_KX022A },
> 	...
> 
> chip_id = device_get_match_data(&i2c->dev);

No, please avoid putting plain integers as pointers of driver_data.

The problem you introduced with your suggestion is impossibility
to distinguish 0 and NULL, beyond other not good things (like missing
castings which are ugly).
  
Matti Vaittinen March 20, 2023, 12:52 p.m. UTC | #9
On 3/20/23 14:34, Jonathan Cameron wrote:
> On Mon, 20 Mar 2023 11:35:06 +0200
> Matti Vaittinen <mazziesaccount@gmail.com> wrote:
> 
>> On 3/17/23 01:48, Mehdi Djait wrote:
>>
>> OTOH, to really benefit from this we should probably pull out the
>> regmap-configs from the kionix-kx022a.c. I am not really sure where we
>> should put it then though. Hence, if there is no good ideas how to split
>> the config and chip-info so they are only available/used where needed -
>> then I am also Ok with the current approach.
> 
> Definitely stick to current approach.  If I had the time I'd
> rip out all the code useing enums in match tables. It's bitten us
> a few times with nasty to track down bugs that only affect more obscure
> ways of binding the driver.
> 

Seems like Jonathan has a strong opinion on this. Please follow his and 
Andy's guidance on this one and forget my comment.


Yours,
	-- Matti
  
kernel test robot March 21, 2023, 1:05 a.m. UTC | #10
Hi Mehdi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on next-20230320]
[cannot apply to linus/master v6.3-rc3]
[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-accelerometer/20230317-075056
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/3ddca10a4c03c3a64afb831cc9dd1e01fe89d305.1679009443.git.mehdi.djait.k%40gmail.com
patch subject: [PATCH 2/3] iio: accel: kionix-kx022a: Add chip_info structure
config: loongarch-randconfig-s032-20230319 (https://download.01.org/0day-ci/archive/20230321/202303210809.RAQ7nfl7-lkp@intel.com/config)
compiler: loongarch64-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/40c75341c42d0e5bea5d73961202978a4be41cd2
        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-accelerometer/20230317-075056
        git checkout 40c75341c42d0e5bea5d73961202978a4be41cd2
        # 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=loongarch 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=loongarch 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/202303210809.RAQ7nfl7-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/iio/accel/kionix-kx022a-spi.c:27:19: sparse: sparse: incorrect type in assignment (different modifiers) @@     expected struct kx022a_chip_info *chip_info @@     got void const * @@
   drivers/iio/accel/kionix-kx022a-spi.c:27:19: sparse:     expected struct kx022a_chip_info *chip_info
   drivers/iio/accel/kionix-kx022a-spi.c:27:19: sparse:     got void const *
>> drivers/iio/accel/kionix-kx022a-spi.c:29:27: sparse: sparse: incorrect type in assignment (different modifiers) @@     expected struct kx022a_chip_info *chip_info @@     got struct kx022a_chip_info const * @@
   drivers/iio/accel/kionix-kx022a-spi.c:29:27: sparse:     expected struct kx022a_chip_info *chip_info
   drivers/iio/accel/kionix-kx022a-spi.c:29:27: sparse:     got struct kx022a_chip_info const *

vim +27 drivers/iio/accel/kionix-kx022a-spi.c

    14	
    15	static int kx022a_spi_probe(struct spi_device *spi)
    16	{
    17		struct device *dev = &spi->dev;
    18		struct kx022a_chip_info *chip_info;
    19		struct regmap *regmap;
    20		const struct spi_device_id *id = spi_get_device_id(spi);
    21	
    22		if (!spi->irq) {
    23			dev_err(dev, "No IRQ configured\n");
    24			return -EINVAL;
    25		}
    26	
  > 27		chip_info = device_get_match_data(&spi->dev);
    28		if (!chip_info)
  > 29			chip_info = (const struct kx022a_chip_info *) id->driver_data;
    30	
    31		regmap = devm_regmap_init_spi(spi, chip_info->regmap_config);
    32		if (IS_ERR(regmap))
    33			return dev_err_probe(dev, PTR_ERR(regmap),
    34					     "Failed to initialize Regmap\n");
    35	
    36		return kx022a_probe_internal(dev, chip_info);
    37	}
    38
  
Mehdi Djait March 21, 2023, 3:39 p.m. UTC | #11
Hello everyone,

On Mon, Mar 20, 2023 at 12:24:47PM +0000, Jonathan Cameron wrote:
> On Mon, 20 Mar 2023 09:17:54 +0200
> Matti Vaittinen <mazziesaccount@gmail.com> wrote:
> 
> > Hi Mehdi and Jonathan,
> > 
> > Just my take on couple of comments from Jonathan :) I still have my own 
> > review to do though...
> > 
> > On 3/19/23 18:20, Jonathan Cameron wrote:
> > > On Fri, 17 Mar 2023 00:48:36 +0100
> > > Mehdi Djait <mehdi.djait.k@gmail.com> wrote:
> > >   
> > >> Refactor the kx022a driver implementation to make it more
> > >> generic and extensible.
> > >> Add the chip_info structure will to the driver's private
> > >> data to hold all the device specific infos.
> > >> Move the enum, struct and constants definitions to the header
> > >> file.  
> > > 
> > > You also introduce an i2c_device_id table
> > > 
> > > Without that I think module autoloading will be broken anyway so that's
> > > definitely a good thing to add.  
> > 
> > I am pretty sure the autoloading worked for OF-systems. But yes, adding 
> > the i2c_device_id is probably a good idea. Thanks.
> 
> Ah. Maybe that issue only occurred for SPI - I'd assumed it was more general.
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/?id=5fa6863ba692
> 
> > 
> > > A few comments inline.  Mostly around reducing the name changes.
> > > Wild cards (or simply shorted 'generic' prefixes like KX_)
> > > almost always bite back in the long run.  Hence we generally just try
> > > to name things after the first device that they were relevant to.  
> > 
> > I must say I disagree on this with you Jonathan. I know wildcards tend 
> > to get confusing - but I still like the idea of showing which of the 
> > definitions are IC specific and which ones are generic or at least used 
> > by more than one variant - especially as long as we only have two 
> > supported ICs. I definitely like the macro naming added by Mehdi. This 
> > approach has been very helpful for me for example in the BD718x7 
> > (BD71837/BD71847/BD71850) PMIC driver. My take on this is:
> > 
> > 1) I like the generic KX_define.
> 
> We already have other kionix drivers that don't use these defines.
> This is less of an issue if they are very local - so pushed down to the C file,
> but I still don't like the implication that they extend to a broad range of
> devices.
> 
> > 2) I would not try adding wildcards like KX_X22 - to denote support for 
> > 122 and 022 - while not supporting 132 - in my experience - that won't 
> > scale.
> 
> I think this already runs into this problem or at least sets the driver
> up to hit it very soon. The reality is that these definitions are shared
> by the 2 parts supported so far.  3rd part comes along and I'd be willing
> to place a bet that at least one of these definitions doesn't apply.
> So we end up with a mess converting it back to a specific name.
> 
> I've gone down this path many times before and it very rarely works out.
> 
> > 3) I definitely like the idea of using exact model number prefix for 
> > 'stuff' which is intended to work only on one exact .
> 
> When you have 2 devices it is easy to separate the 'generic' from the
> 'specific'.  That breaks when you have 3. If we are sure there won't be
> a 3rd device supported by this driver then fair enough...
> 
> > 
> > Regarding the 3) - I am not so strict on how the register/mask defines 
> > are handled - I _like_ the 1) 2) 3) approach above - but mask/register 
> > defines tend to get set (correctly) once and not required to be looked 
> > up after this. But. When the 'stuff' is functions - this gets very 
> > useful as one is very often required to see which functions are executed 
> > on which IC variant. Same goes to structs.
> 
> Given they tend to be accessed via a function pointer, even functions
> are only set up the once.  For these I'm fine with a nasty listing
> type approach with multiple part names in the function defintion.
> That doesn't scale great either as lots of parts get added but it at least
> calls out which function covers which parts.
> 
> > 
> > So, if we manage to convince Jonathan about the naming, then I like what 
> > yoo had here! I would hovever do it in two steps. I would at first do 
> > renaming patch where the generic defines were renamed - without any 
> > functional changes - and only then add the kx132 stuff in a subsequent 
> > patch. That would simplify seeing which changes are just renaming and 
> > which are functional ones.
> > 
> > But here, I must go with the wind - if subsystem maintainer says the 
> > code should not have naming like this - then I have no say over it... :/
> 
> If we have truely universal defines - sometimes this happens for WHO AM I 
> registers for example as they are the same over all devices from a manufacturer
> (more or less anyway) then the broad forms are fine.  Otherwise it just tends
> to end up as a mess if lots of parts added.

I will remove the generic defines. 

I also really liked the idea of seperating the IC specific stuff from the 
generic ones. Better play it safe here, I can also see it becoming a mess in
the long run. 

> > 
> > >>   
> > >> +static const struct i2c_device_id kx022a_i2c_id[] = {
> > >> +	{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx_chip_info[KX022A] },  
> > > If there are a small set and we aren't ever going to index the chip_info structure
> > > we might be better off not bothering with the enum and instead using a separate
> > > instance of the structure for each chip.
> > >   
> > 
> > I kind of like also the table added by Mehdi. I admit I was at first 
> > just thinking that we should have a pointer to the struct here without 
> > any tables - but... After I took a peek in the kionix-kx022a.c - I kind 
> > of liked the table and not exporting the struct names. So, I don't have 
> > a strong opinion on this.
> > 
> > I think it's worth noting that this driver could (maybe easily enough) 
> > be extended to support also a few other kionix accelerometers. Maybe, if 
> > we don't scare Mehdi away, we will see a few other variants supported as 
> > well ;)
> 
> This one wasn't a particularly important bit of feedback. I'm fine with the
> table, though seems slightly less readable to my eyes.

My reasoning behind it: when supporting multiple devices, having a single
array of chip_info and one single EXPORT_SYMBOL is more concise and
readable. 

> 
> > 
> > >>   	data->regmap = regmap;
> > >>   	data->dev = dev;
> > >>   	data->irq = irq;
> > >> -	data->odr_ns = KX022A_DEFAULT_PERIOD_NS;
> > >> +	data->odr_ns = KX_DEFAULT_PERIOD_NS;
> > >>   	mutex_init(&data->mutex);
> > >>   
> > >> -	idev->channels = kx022a_channels;
> > >> -	idev->num_channels = ARRAY_SIZE(kx022a_channels);
> > >> -	idev->name = "kx022-accel";  
> > > 
> > > Ah. Missed this naming in original driver review.  We only normally
> > > postfix with accel in devices that have multiple sensors with separate
> > > drivers. Don't think that is true of the kx022a.  
> > 
> > Ouch. I am not 100% sure but may be you didn't miss it. It may be I just 
> > missed fixing this because your comment here sounds somewhat familiar to 
> > me! (Or then you commented on suffix in driver-name).
> 
> Meh. This stuff happens and at the end of the day it's a magic string
> that userspace can match against.  No userspace knows all of them anyway
> so most likely it's just provided in a 'selection' box for a user or encoded
> in a custom script / config file.  So not hugely important for it to have
> the simplest possible form.
> 
> > 
> > > It's ABI so we are stuck with it, but avoid repeating that issue
> > > for new devices. >  

I will change the name in the chip_info of kx022a back to "kx022-accel"

I am already using "kx132" as name for the newly supported device

> > 
> > >>   
> > >> +enum kx022a_device_type {
> > >> +	KX022A,
> > >> +};  
> > > 
> > > As below. I'd avoid using the enum unless needed.
> > > That can make sense where a driver supports lots of devices but I don't think
> > > it does here.  
> > 
> > Well, I know it is usually not too clever to be prepared for the future 
> > stuff too well. But - I don't think the enum and table are adding much 
> > of complexity? I am saying this as I think this driver could be extended 
> > to support also kx022 (without the A), kx023, kx122. I've also seen some 
> > references to model kx022A-120B (but I have no idea what's the story 
> > there or if that IC is publicly available). Maybe Mehdi would like to 
> > extend this driver further after the KX132 is done ;)

Yes, my goal is to support more devices and I want to make as easy as 
possible to extend this driver :)

> 
> Not adding a lot, but you are going to end up with adding one line
> to an enum in the header for each new device, vs one
> extern line.  So I'm not sure it saves anything either.
> 

Using a separate instance of the chip_info structure for each chip means
also an extra symbol export

> > 
> > >> -int kx022a_probe_internal(struct device *dev);
> > >> -extern const struct regmap_config kx022a_regmap;
> > >> +struct kx022a_chip_info {
> > >> +	const char *name;
> > >> +	enum kx022a_device_type type;
> > >> +	const struct regmap_config *regmap_config;
> > >> +	const struct iio_chan_spec *channels;
> > >> +	unsigned int num_channels;
> > >> +	unsigned int fifo_length;
> > >> +	u8 who;  
> > > Some of these are no immediately obvious so either rename the
> > > field so it is more obvious what it is, or add comments.  
> > 
> > I would vote for adding a comment :) I like the who. Both the band and 
> > this member here :) Data-sheet has register named as "who_am_i" - so I 
> > don't think this name is too obfuscating - and what matters to me - it 
> > is short yet meaningful.
> > 
> > >> +	u8 id;
> > >> +	u8 cntl;
> > >> +	u8 cntl2;
> > >> +	u8 odcntl;
> > >> +	u8 buf_cntl1;
> > >> +	u8 buf_cntl2;
> > >> +	u8 buf_clear;
> > >> +	u8 buf_status1;
> > >> +	u16 buf_smp_lvl_mask;
> > >> +	u8 buf_read;
> > >> +	u8 inc1;
> > >> +	u8 inc4;
> > >> +	u8 inc5;
> > >> +	u8 inc6;
> > >> +	u8 xout_l;
> > >> +};
> > >> +
> > >> +struct kx022a_data {  
> > > 
> > > Why move this to the header?  Unless there is a strong reason
> > > I'd prefer this to stay down in the .c file.  
> > 
> > So would I. It's definitely nice to be able to see the struct in the 
> > same file where the code referencing it is.

no strong reason, I will move it back to the .c file

--
Kind Regards
Mehdi Djait
  
Mehdi Djait March 21, 2023, 3:56 p.m. UTC | #12
Hello Matti,

> > +static int kx022a_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);
> > +
> > +	/*
> > +	 * The KX022A has FIFO which can store 43 samples of HiRes data from 2
> > +	 * channels. This equals to 43 (samples) * 3 (channels) * 2 (bytes/sample) to
> > +	 * 258 bytes of sample data. The quirk to know is that the amount of bytes in
> > +	 * the FIFO is advertised via 8 bit register (max value 255). The thing to note
> > +	 * is that full 258 bytes of data is indicated using the max value 255.
> > +	 */
> > +	if (data->chip_info->type == KX022A && fifo_bytes == KX022A_FIFO_FULL_VALUE)
> > +		fifo_bytes = KX022A_FIFO_MAX_BYTES;
> > +
> > +	if (fifo_bytes % KX_FIFO_SAMPLES_SIZE_BYTES)
> > +		dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
> > +
> > +	return fifo_bytes;
> > +}
> 
> I like adding this function. Here I agree with Jonathan - having a device
> specific functions would clarify this a bit. The KX022A "quirk" is a bit
> confusing. You could then get rid of the buf_smp_lvl_mask.

my bad here, I should have made a separate patch and explained more ...
buf_smp_lvl_mask is essential because kionix products use different
number of bits to report "the number of data bytes that have been stored in the 
sample buffer" using the registers BUF_STATUS_1 and BUF_STATUS_2

kx022a: 8bits
kx132: 10bits
kx12x: 11bits
kx126: 12bits

I think this function is quite generic and can be used for different
kionix devices: 

- It reads BUF_STATUS_1 and BUF_STATUS_2 and then uses a chip specific
mask 
- It takes care of the quirk of kx022a which is just a simple if statement 

> 
> > +
> >   static int kx022a_drop_fifo_contents(struct kx022a_data *data)
> >   {
> >   	/*
> > @@ -593,35 +588,22 @@ static int kx022a_drop_fifo_contents(struct kx022a_data *data)
> >   	 */
> >   	data->timestamp = 0;
> > -	return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0);
> > +	return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0);
> >   }
> >   static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
> >   			       bool irq)
> >   {
> >   	struct kx022a_data *data = iio_priv(idev);
> > -	struct device *dev = regmap_get_device(data->regmap);
> > -	__le16 buffer[KX022A_FIFO_LENGTH * 3];
> > +	__le16 buffer[data->chip_info->fifo_length * 3];
> 
> I don't like this. Having the length of an array decided at run-time is not
> something I appreciate. Maybe you could just always reserve the memory so
> that the largest FIFO gets supported. I am just wondering how large arrays
> we can safely allocate from the stack?

I was stupid enough to ignore the warnings... 
I will take care of it in the v2

> 
> 
> > @@ -812,14 +792,14 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
> >   		goto unlock_out;
> >   	/* Enable buffer */
> > -	ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
> > -			      KX022A_MASK_BUF_EN);
> > +	ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
> > +			      KX_MASK_BUF_EN);
> >   	if (ret)
> >   		goto unlock_out;
> > -	data->state |= KX022A_STATE_FIFO;
> > +	data->state |= KX_STATE_FIFO;
> >   	ret = regmap_set_bits(data->regmap, data->ien_reg,
> > -			      KX022A_MASK_WMI);
> > +			      KX_MASK_WMI);
> 
> I think this fits to one line now. (even on my screen)
> 
> >   	if (ret)
> >   		goto unlock_out;
> 
> > -int kx022a_probe_internal(struct device *dev)
> > +int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)
> 
> As mentioned elsewhere, this might also work if the chip-type enum was
> passed here as parameter. That way the bus specific part would not need to
> know about the struct chip_info...
> 
> >   {
> >   	static const char * const regulator_names[] = {"io-vdd", "vdd"};
> >   	struct iio_trigger *indio_trig;
> > @@ -1023,6 +1003,7 @@ int kx022a_probe_internal(struct device *dev)
> >   		return -ENOMEM;
> >   	data = iio_priv(idev);
> > +	data->chip_info = chip_info;
> 
> ...Here you could then pick the correct chip_info based on the chip-type
> enum. In that case I'd like to get the regmap_config(s) in own file. Not
> sure how that would look like though.
> 
> All in all, I like how this looks like. Nice job!

Thank you for the feedback :)

--
Kind Regards 
Mehdi Djait
  
Matti Vaittinen March 22, 2023, 6:37 a.m. UTC | #13
On 3/21/23 17:56, Mehdi Djait wrote:
> Hello Matti,
> 
>>> +static int kx022a_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);
>>> +
>>> +	/*
>>> +	 * The KX022A has FIFO which can store 43 samples of HiRes data from 2
>>> +	 * channels. This equals to 43 (samples) * 3 (channels) * 2 (bytes/sample) to
>>> +	 * 258 bytes of sample data. The quirk to know is that the amount of bytes in
>>> +	 * the FIFO is advertised via 8 bit register (max value 255). The thing to note
>>> +	 * is that full 258 bytes of data is indicated using the max value 255.
>>> +	 */
>>> +	if (data->chip_info->type == KX022A && fifo_bytes == KX022A_FIFO_FULL_VALUE)
>>> +		fifo_bytes = KX022A_FIFO_MAX_BYTES;
>>> +
>>> +	if (fifo_bytes % KX_FIFO_SAMPLES_SIZE_BYTES)
>>> +		dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
>>> +
>>> +	return fifo_bytes;
>>> +}
>>
>> I like adding this function. Here I agree with Jonathan - having a device
>> specific functions would clarify this a bit. The KX022A "quirk" is a bit
>> confusing. You could then get rid of the buf_smp_lvl_mask.
> 
> my bad here, I should have made a separate patch and explained more ...
> buf_smp_lvl_mask is essential because kionix products use different
> number of bits to report "the number of data bytes that have been stored in the
> sample buffer" using the registers BUF_STATUS_1 and BUF_STATUS_2

Yes, they have different size of FIFO, and the KX022A does also have the 
nasty "FIFO FULL" quirk. Due to this quirk and other differences I was 
suggesting you created own functions for kx022a and kx132. Eg something 
along the lines:

static int kx022a_get_fifo_bytes(struct kx022a_data *data)
{
...
}
static int kx132_get_fifo_bytes(struct kx022a_data *data)
{
...
}

struct chip_info {
	...
	int (*fifo_bytes)(struct kx022a_data *);
};

and do the:
fifo_bytes = kx022a_get_fifo_bytes;
or
fifo_bytes = kx132_get_fifo_bytes;

in probe. That will also remove the need to check the IC variant for 
each FIFO read.

If you did that you could remove the buf_smp_lvl_mask and maybe also the 
buf_statusX members from the chip_info struct (at least for now). You 
could also do regular read for KX022A and drop the endianess conversion 
for it. Bulk read is only needed for ICs with more than 8bits of FIFO 
status. Furthermore, the IC-type check could then go away and the above 
mentioned KX022A-specific handling would not be obfuscating the kx132 code.

> 
> kx022a: 8bits
> kx132: 10bits
> kx12x: 11bits
> kx126: 12bits
> 
> I think this function is quite generic and can be used for different
> kionix devices:
> 
> - It reads BUF_STATUS_1 and BUF_STATUS_2 and then uses a chip specific
> mask
> - It takes care of the quirk of kx022a which is just a simple if statement

Yes. Your function definitely works. And I do like the fact that you did 
own function for the "amount of data in fifo"-check. Still, the code 
would be little simpler and perform a tiny bit better if you did two 
functions instead of one.

Yours,
	-- Matti
  

Patch

diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c
index e6fd02d931b6..21c4c0ae1a68 100644
--- a/drivers/iio/accel/kionix-kx022a-i2c.c
+++ b/drivers/iio/accel/kionix-kx022a-i2c.c
@@ -15,23 +15,35 @@ 
 static int kx022a_i2c_probe(struct i2c_client *i2c)
 {
 	struct device *dev = &i2c->dev;
+	struct kx022a_chip_info *chip_info;
 	struct regmap *regmap;
+	const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
 
 	if (!i2c->irq) {
 		dev_err(dev, "No IRQ configured\n");
 		return -EINVAL;
 	}
 
-	regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap);
+	chip_info = device_get_match_data(&i2c->dev);
+	if (!chip_info)
+		chip_info = (const struct kx022a_chip_info *) id->driver_data;
+
+	regmap = devm_regmap_init_i2c(i2c, chip_info->regmap_config);
 	if (IS_ERR(regmap))
 		return dev_err_probe(dev, PTR_ERR(regmap),
 				     "Failed to initialize Regmap\n");
 
-	return kx022a_probe_internal(dev);
+	return kx022a_probe_internal(dev, chip_info);
 }
 
+static const struct i2c_device_id kx022a_i2c_id[] = {
+	{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx_chip_info[KX022A] },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
+
 static const struct of_device_id kx022a_of_match[] = {
-	{ .compatible = "kionix,kx022a", },
+	{ .compatible = "kionix,kx022a", .data = &kx_chip_info[KX022A] },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, kx022a_of_match);
@@ -42,6 +54,7 @@  static struct i2c_driver kx022a_i2c_driver = {
 		.of_match_table = kx022a_of_match,
 	  },
 	.probe_new    = kx022a_i2c_probe,
+	.id_table     = kx022a_i2c_id,
 };
 module_i2c_driver(kx022a_i2c_driver);
 
diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c
index 9cd047f7b346..ec076af0f261 100644
--- a/drivers/iio/accel/kionix-kx022a-spi.c
+++ b/drivers/iio/accel/kionix-kx022a-spi.c
@@ -15,40 +15,46 @@ 
 static int kx022a_spi_probe(struct spi_device *spi)
 {
 	struct device *dev = &spi->dev;
+	struct kx022a_chip_info *chip_info;
 	struct regmap *regmap;
+	const struct spi_device_id *id = spi_get_device_id(spi);
 
 	if (!spi->irq) {
 		dev_err(dev, "No IRQ configured\n");
 		return -EINVAL;
 	}
 
-	regmap = devm_regmap_init_spi(spi, &kx022a_regmap);
+	chip_info = device_get_match_data(&spi->dev);
+	if (!chip_info)
+		chip_info = (const struct kx022a_chip_info *) id->driver_data;
+
+	regmap = devm_regmap_init_spi(spi, chip_info->regmap_config);
 	if (IS_ERR(regmap))
 		return dev_err_probe(dev, PTR_ERR(regmap),
 				     "Failed to initialize Regmap\n");
 
-	return kx022a_probe_internal(dev);
+	return kx022a_probe_internal(dev, chip_info);
 }
 
-static const struct spi_device_id kx022a_id[] = {
-	{ "kx022a" },
+static const struct spi_device_id kx022a_spi_id[] = {
+	{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx_chip_info[KX022A] },
 	{ }
 };
-MODULE_DEVICE_TABLE(spi, kx022a_id);
+MODULE_DEVICE_TABLE(spi, kx022a_spi_id);
 
 static const struct of_device_id kx022a_of_match[] = {
-	{ .compatible = "kionix,kx022a", },
+	{ .compatible = "kionix,kx022a", .data = &kx_chip_info[KX022A] },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, kx022a_of_match);
 
 static struct spi_driver kx022a_spi_driver = {
 	.driver = {
-		.name   = "kx022a-spi",
+		.name	= "kx022a-spi",
 		.of_match_table = kx022a_of_match,
 	},
 	.probe = kx022a_spi_probe,
-	.id_table = kx022a_id,
+	.id_table = kx022a_spi_id,
 };
 module_spi_driver(kx022a_spi_driver);
 
diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c
index 8dac0337c249..27e8642aa8f5 100644
--- a/drivers/iio/accel/kionix-kx022a.c
+++ b/drivers/iio/accel/kionix-kx022a.c
@@ -26,29 +26,7 @@ 
 
 #include "kionix-kx022a.h"
 
-/*
- * The KX022A has FIFO which can store 43 samples of HiRes data from 2
- * channels. This equals to 43 (samples) * 3 (channels) * 2 (bytes/sample) to
- * 258 bytes of sample data. The quirk to know is that the amount of bytes in
- * the FIFO is advertised via 8 bit register (max value 255). The thing to note
- * is that full 258 bytes of data is indicated using the max value 255.
- */
-#define KX022A_FIFO_LENGTH			43
-#define KX022A_FIFO_FULL_VALUE			255
-#define KX022A_SOFT_RESET_WAIT_TIME_US		(5 * USEC_PER_MSEC)
-#define KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US	(500 * USEC_PER_MSEC)
-
-/* 3 axis, 2 bytes of data for each of the axis */
-#define KX022A_FIFO_SAMPLES_SIZE_BYTES		6
-#define KX022A_FIFO_MAX_BYTES					\
-	(KX022A_FIFO_LENGTH * KX022A_FIFO_SAMPLES_SIZE_BYTES)
-
-enum {
-	KX022A_STATE_SAMPLE,
-	KX022A_STATE_FIFO,
-};
-
-/* Regmap configs */
+/* kx022a Regmap configs */
 static const struct regmap_range kx022a_volatile_ranges[] = {
 	{
 		.range_min = KX022A_REG_XHP_L,
@@ -138,7 +116,7 @@  static const struct regmap_access_table kx022a_nir_regs = {
 	.n_yes_ranges = ARRAY_SIZE(kx022a_noinc_read_ranges),
 };
 
-const struct regmap_config kx022a_regmap = {
+static const struct regmap_config kx022a_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
 	.volatile_table = &kx022a_volatile_regs,
@@ -149,39 +127,6 @@  const struct regmap_config kx022a_regmap = {
 	.max_register = KX022A_MAX_REGISTER,
 	.cache_type = REGCACHE_RBTREE,
 };
-EXPORT_SYMBOL_NS_GPL(kx022a_regmap, IIO_KX022A);
-
-struct kx022a_data {
-	struct regmap *regmap;
-	struct iio_trigger *trig;
-	struct device *dev;
-	struct iio_mount_matrix orientation;
-	int64_t timestamp, old_timestamp;
-
-	int irq;
-	int inc_reg;
-	int ien_reg;
-
-	unsigned int state;
-	unsigned int odr_ns;
-
-	bool trigger_enabled;
-	/*
-	 * Prevent toggling the sensor stby/active state (PC1 bit) in the
-	 * middle of a configuration, or when the fifo is enabled. Also,
-	 * protect the data stored/retrieved from this structure from
-	 * concurrent accesses.
-	 */
-	struct mutex mutex;
-	u8 watermark;
-
-	/* 3 x 16bit accel data + timestamp */
-	__le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
-	struct {
-		__le16 channels[3];
-		s64 ts __aligned(8);
-	} scan;
-};
 
 static const struct iio_mount_matrix *
 kx022a_get_mount_matrix(const struct iio_dev *idev,
@@ -192,13 +137,6 @@  kx022a_get_mount_matrix(const struct iio_dev *idev,
 	return &data->orientation;
 }
 
-enum {
-	AXIS_X,
-	AXIS_Y,
-	AXIS_Z,
-	AXIS_MAX
-};
-
 static const unsigned long kx022a_scan_masks[] = {
 	BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), 0
 };
@@ -208,7 +146,7 @@  static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
 	{ }
 };
 
-#define KX022A_ACCEL_CHAN(axis, index)				\
+#define KX022A_ACCEL_CHAN(axis, index, device)			\
 {								\
 	.type = IIO_ACCEL,					\
 	.modified = 1,						\
@@ -220,7 +158,7 @@  static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
 				BIT(IIO_CHAN_INFO_SCALE) |	\
 				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
 	.ext_info = kx022a_ext_info,				\
-	.address = KX022A_REG_##axis##OUT_L,			\
+	.address = device##_REG_##axis##OUT_L,			\
 	.scan_index = index,					\
 	.scan_type = {                                          \
 		.sign = 's',					\
@@ -231,9 +169,9 @@  static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
 }
 
 static const struct iio_chan_spec kx022a_channels[] = {
-	KX022A_ACCEL_CHAN(X, 0),
-	KX022A_ACCEL_CHAN(Y, 1),
-	KX022A_ACCEL_CHAN(Z, 2),
+	KX022A_ACCEL_CHAN(X, 0, KX022A),
+	KX022A_ACCEL_CHAN(Y, 1, KX022A),
+	KX022A_ACCEL_CHAN(Z, 2, KX022A),
 	IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
@@ -286,6 +224,34 @@  static const int kx022a_scale_table[][2] = {
 	{ 4788, 403320 },
 };
 
+const struct kx022a_chip_info kx_chip_info[] = {
+	[KX022A] = {
+		.name		  = "kx022a",
+		.type		  = KX022A,
+		.regmap_config	  = &kx022a_regmap_config,
+		.channels	  = kx022a_channels,
+		.num_channels	  = ARRAY_SIZE(kx022a_channels),
+		.fifo_length	  = KX022A_FIFO_LENGTH,
+		.who		  = KX022A_REG_WHO,
+		.id		  = KX022A_ID,
+		.cntl		  = KX022A_REG_CNTL,
+		.cntl2		  = KX022A_REG_CNTL2,
+		.odcntl		  = KX022A_REG_ODCNTL,
+		.buf_cntl1	  = KX022A_REG_BUF_CNTL1,
+		.buf_cntl2	  = KX022A_REG_BUF_CNTL2,
+		.buf_clear	  = KX022A_REG_BUF_CLEAR,
+		.buf_status1	  = KX022A_REG_BUF_STATUS_1,
+		.buf_smp_lvl_mask = KX022A_MASK_BUF_SMP_LVL,
+		.buf_read	  = KX022A_REG_BUF_READ,
+		.inc1		  = KX022A_REG_INC1,
+		.inc4		  = KX022A_REG_INC4,
+		.inc5		  = KX022A_REG_INC5,
+		.inc6		  = KX022A_REG_INC6,
+		.xout_l		  = KX022A_REG_XOUT_L,
+	},
+};
+EXPORT_SYMBOL_NS_GPL(kx_chip_info, IIO_KX022A);
+
 static int kx022a_read_avail(struct iio_dev *indio_dev,
 			     struct iio_chan_spec const *chan,
 			     const int **vals, int *type, int *length,
@@ -309,19 +275,17 @@  static int kx022a_read_avail(struct iio_dev *indio_dev,
 	}
 }
 
-#define KX022A_DEFAULT_PERIOD_NS (20 * NSEC_PER_MSEC)
-
 static void kx022a_reg2freq(unsigned int val,  int *val1, int *val2)
 {
-	*val1 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][0];
-	*val2 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][1];
+	*val1 = kx022a_accel_samp_freq_table[val & KX_MASK_ODR][0];
+	*val2 = kx022a_accel_samp_freq_table[val & KX_MASK_ODR][1];
 }
 
 static void kx022a_reg2scale(unsigned int val, unsigned int *val1,
 			     unsigned int *val2)
 {
-	val &= KX022A_MASK_GSEL;
-	val >>= KX022A_GSEL_SHIFT;
+	val &= KX_MASK_GSEL;
+	val >>= KX_GSEL_SHIFT;
 
 	*val1 = kx022a_scale_table[val][0];
 	*val2 = kx022a_scale_table[val][1];
@@ -332,11 +296,11 @@  static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on)
 	int ret;
 
 	if (on)
-		ret = regmap_set_bits(data->regmap, KX022A_REG_CNTL,
-				      KX022A_MASK_PC1);
+		ret = regmap_set_bits(data->regmap, data->chip_info->cntl,
+				      KX_MASK_PC1);
 	else
-		ret = regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
-					KX022A_MASK_PC1);
+		ret = regmap_clear_bits(data->regmap, data->chip_info->cntl,
+					KX_MASK_PC1);
 	if (ret)
 		dev_err(data->dev, "Turn %s fail %d\n", str_on_off(on), ret);
 
@@ -403,8 +367,8 @@  static int kx022a_write_raw(struct iio_dev *idev,
 			break;
 
 		ret = regmap_update_bits(data->regmap,
-					 KX022A_REG_ODCNTL,
-					 KX022A_MASK_ODR, n);
+					 data->chip_info->odcntl,
+					 KX_MASK_ODR, n);
 		data->odr_ns = kx022a_odrs[n];
 		kx022a_turn_on_unlock(data);
 		break;
@@ -424,9 +388,9 @@  static int kx022a_write_raw(struct iio_dev *idev,
 		if (ret)
 			break;
 
-		ret = regmap_update_bits(data->regmap, KX022A_REG_CNTL,
-					 KX022A_MASK_GSEL,
-					 n << KX022A_GSEL_SHIFT);
+		ret = regmap_update_bits(data->regmap, data->chip_info->cntl,
+					 KX_MASK_GSEL,
+					 n << KX_GSEL_SHIFT);
 		kx022a_turn_on_unlock(data);
 		break;
 	default:
@@ -446,8 +410,8 @@  static int kx022a_fifo_set_wmi(struct kx022a_data *data)
 
 	threshold = data->watermark;
 
-	return regmap_update_bits(data->regmap, KX022A_REG_BUF_CNTL1,
-				  KX022A_MASK_WM_TH, threshold);
+	return regmap_update_bits(data->regmap, data->chip_info->buf_cntl1,
+				  KX_MASK_WM_TH, threshold);
 }
 
 static int kx022a_get_axis(struct kx022a_data *data,
@@ -489,11 +453,11 @@  static int kx022a_read_raw(struct iio_dev *idev,
 		return ret;
 
 	case IIO_CHAN_INFO_SAMP_FREQ:
-		ret = regmap_read(data->regmap, KX022A_REG_ODCNTL, &regval);
+		ret = regmap_read(data->regmap, data->chip_info->odcntl, &regval);
 		if (ret)
 			return ret;
 
-		if ((regval & KX022A_MASK_ODR) >
+		if ((regval & KX_MASK_ODR) >
 		    ARRAY_SIZE(kx022a_accel_samp_freq_table)) {
 			dev_err(data->dev, "Invalid ODR\n");
 			return -EINVAL;
@@ -504,7 +468,7 @@  static int kx022a_read_raw(struct iio_dev *idev,
 		return IIO_VAL_INT_PLUS_MICRO;
 
 	case IIO_CHAN_INFO_SCALE:
-		ret = regmap_read(data->regmap, KX022A_REG_CNTL, &regval);
+		ret = regmap_read(data->regmap, data->chip_info->cntl, &regval);
 		if (ret < 0)
 			return ret;
 
@@ -531,8 +495,8 @@  static int kx022a_set_watermark(struct iio_dev *idev, unsigned int val)
 {
 	struct kx022a_data *data = iio_priv(idev);
 
-	if (val > KX022A_FIFO_LENGTH)
-		val = KX022A_FIFO_LENGTH;
+	if (val > data->chip_info->fifo_length)
+		val = data->chip_info->fifo_length;
 
 	mutex_lock(&data->mutex);
 	data->watermark = val;
@@ -580,6 +544,37 @@  static const struct iio_dev_attr *kx022a_fifo_attributes[] = {
 	NULL
 };
 
+static int kx022a_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);
+
+	/*
+	 * The KX022A has FIFO which can store 43 samples of HiRes data from 2
+	 * channels. This equals to 43 (samples) * 3 (channels) * 2 (bytes/sample) to
+	 * 258 bytes of sample data. The quirk to know is that the amount of bytes in
+	 * the FIFO is advertised via 8 bit register (max value 255). The thing to note
+	 * is that full 258 bytes of data is indicated using the max value 255.
+	 */
+	if (data->chip_info->type == KX022A && fifo_bytes == KX022A_FIFO_FULL_VALUE)
+		fifo_bytes = KX022A_FIFO_MAX_BYTES;
+
+	if (fifo_bytes % KX_FIFO_SAMPLES_SIZE_BYTES)
+		dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
+
+	return fifo_bytes;
+}
+
 static int kx022a_drop_fifo_contents(struct kx022a_data *data)
 {
 	/*
@@ -593,35 +588,22 @@  static int kx022a_drop_fifo_contents(struct kx022a_data *data)
 	 */
 	data->timestamp = 0;
 
-	return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0);
+	return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0);
 }
 
 static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
 			       bool irq)
 {
 	struct kx022a_data *data = iio_priv(idev);
-	struct device *dev = regmap_get_device(data->regmap);
-	__le16 buffer[KX022A_FIFO_LENGTH * 3];
+	__le16 buffer[data->chip_info->fifo_length * 3];
 	uint64_t sample_period;
 	int count, fifo_bytes;
 	bool renable = false;
 	int64_t tstamp;
 	int ret, i;
 
-	ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes);
-	if (ret) {
-		dev_err(dev, "Error reading buffer status\n");
-		return ret;
-	}
-
-	/* Let's not overflow if we for some reason get bogus value from i2c */
-	if (fifo_bytes == KX022A_FIFO_FULL_VALUE)
-		fifo_bytes = KX022A_FIFO_MAX_BYTES;
-
-	if (fifo_bytes % KX022A_FIFO_SAMPLES_SIZE_BYTES)
-		dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
-
-	count = fifo_bytes / KX022A_FIFO_SAMPLES_SIZE_BYTES;
+	fifo_bytes = kx022a_get_fifo_bytes(data);
+	count = fifo_bytes / KX_FIFO_SAMPLES_SIZE_BYTES;
 	if (!count)
 		return 0;
 
@@ -679,8 +661,8 @@  static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
 		count = samples;
 	}
 
-	fifo_bytes = count * KX022A_FIFO_SAMPLES_SIZE_BYTES;
-	ret = regmap_noinc_read(data->regmap, KX022A_REG_BUF_READ,
+	fifo_bytes = count * KX_FIFO_SAMPLES_SIZE_BYTES;
+	ret = regmap_noinc_read(data->regmap, data->chip_info->buf_read,
 				&buffer[0], fifo_bytes);
 	if (ret)
 		goto renable_out;
@@ -733,20 +715,18 @@  static const struct iio_info kx022a_info = {
 static int kx022a_set_drdy_irq(struct kx022a_data *data, bool en)
 {
 	if (en)
-		return regmap_set_bits(data->regmap, KX022A_REG_CNTL,
-				       KX022A_MASK_DRDY);
+		return regmap_set_bits(data->regmap, data->chip_info->cntl,
+				       KX_MASK_DRDY);
 
-	return regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
-				 KX022A_MASK_DRDY);
+	return regmap_clear_bits(data->regmap, data->chip_info->cntl,
+				 KX_MASK_DRDY);
 }
 
 static int kx022a_prepare_irq_pin(struct kx022a_data *data)
 {
 	/* Enable IRQ1 pin. Set polarity to active low */
-	int mask = KX022A_MASK_IEN | KX022A_MASK_IPOL |
-		   KX022A_MASK_ITYP;
-	int val = KX022A_MASK_IEN | KX022A_IPOL_LOW |
-		  KX022A_ITYP_LEVEL;
+	int mask = KX_MASK_IEN | KX_MASK_IPOL | KX_MASK_ITYP;
+	int val = KX_MASK_IEN | KX_IPOL_LOW | KX_ITYP_LEVEL;
 	int ret;
 
 	ret = regmap_update_bits(data->regmap, data->inc_reg, mask, val);
@@ -754,7 +734,7 @@  static int kx022a_prepare_irq_pin(struct kx022a_data *data)
 		return ret;
 
 	/* We enable WMI to IRQ pin only at buffer_enable */
-	mask = KX022A_MASK_INS2_DRDY;
+	mask = KX_MASK_INS2_DRDY;
 
 	return regmap_set_bits(data->regmap, data->ien_reg, mask);
 }
@@ -767,16 +747,16 @@  static int kx022a_fifo_disable(struct kx022a_data *data)
 	if (ret)
 		return ret;
 
-	ret = regmap_clear_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI);
+	ret = regmap_clear_bits(data->regmap, data->ien_reg, KX_MASK_WMI);
 	if (ret)
 		goto unlock_out;
 
-	ret = regmap_clear_bits(data->regmap, KX022A_REG_BUF_CNTL2,
-				KX022A_MASK_BUF_EN);
+	ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2,
+				KX_MASK_BUF_EN);
 	if (ret)
 		goto unlock_out;
 
-	data->state &= ~KX022A_STATE_FIFO;
+	data->state &= ~KX_STATE_FIFO;
 
 	kx022a_drop_fifo_contents(data);
 
@@ -812,14 +792,14 @@  static int kx022a_fifo_enable(struct kx022a_data *data)
 		goto unlock_out;
 
 	/* Enable buffer */
-	ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
-			      KX022A_MASK_BUF_EN);
+	ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
+			      KX_MASK_BUF_EN);
 	if (ret)
 		goto unlock_out;
 
-	data->state |= KX022A_STATE_FIFO;
+	data->state |= KX_STATE_FIFO;
 	ret = regmap_set_bits(data->regmap, data->ien_reg,
-			      KX022A_MASK_WMI);
+			      KX_MASK_WMI);
 	if (ret)
 		goto unlock_out;
 
@@ -858,8 +838,8 @@  static irqreturn_t kx022a_trigger_handler(int irq, void *p)
 	struct kx022a_data *data = iio_priv(idev);
 	int ret;
 
-	ret = regmap_bulk_read(data->regmap, KX022A_REG_XOUT_L, data->buffer,
-			       KX022A_FIFO_SAMPLES_SIZE_BYTES);
+	ret = regmap_bulk_read(data->regmap, data->chip_info->xout_l, data->buffer,
+			       KX_FIFO_SAMPLES_SIZE_BYTES);
 	if (ret < 0)
 		goto err_read;
 
@@ -879,7 +859,7 @@  static irqreturn_t kx022a_irq_handler(int irq, void *private)
 	data->old_timestamp = data->timestamp;
 	data->timestamp = iio_get_time_ns(idev);
 
-	if (data->state & KX022A_STATE_FIFO || data->trigger_enabled)
+	if (data->state & KX_STATE_FIFO || data->trigger_enabled)
 		return IRQ_WAKE_THREAD;
 
 	return IRQ_NONE;
@@ -903,10 +883,10 @@  static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
 		ret = IRQ_HANDLED;
 	}
 
-	if (data->state & KX022A_STATE_FIFO) {
+	if (data->state & KX_STATE_FIFO) {
 		int ok;
 
-		ok = __kx022a_fifo_flush(idev, KX022A_FIFO_LENGTH, true);
+		ok = __kx022a_fifo_flush(idev, data->chip_info->fifo_length, true);
 		if (ok > 0)
 			ret = IRQ_HANDLED;
 	}
@@ -927,7 +907,7 @@  static int kx022a_trigger_set_state(struct iio_trigger *trig,
 	if (data->trigger_enabled == state)
 		goto unlock_out;
 
-	if (data->state & KX022A_STATE_FIFO) {
+	if (data->state & KX_STATE_FIFO) {
 		dev_warn(data->dev, "Can't set trigger when FIFO enabled\n");
 		ret = -EBUSY;
 		goto unlock_out;
@@ -959,7 +939,7 @@  static int kx022a_chip_init(struct kx022a_data *data)
 	int ret, val;
 
 	/* Reset the senor */
-	ret = regmap_write(data->regmap, KX022A_REG_CNTL2, KX022A_MASK_SRST);
+	ret = regmap_write(data->regmap, data->chip_info->cntl2, KX_MASK_SRST);
 	if (ret)
 		return ret;
 
@@ -969,25 +949,25 @@  static int kx022a_chip_init(struct kx022a_data *data)
 	 */
 	msleep(1);
 
-	ret = regmap_read_poll_timeout(data->regmap, KX022A_REG_CNTL2, val,
-				       !(val & KX022A_MASK_SRST),
-				       KX022A_SOFT_RESET_WAIT_TIME_US,
-				       KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US);
+	ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val,
+				       !(val & KX_MASK_SRST),
+				       KX_SOFT_RESET_WAIT_TIME_US,
+				       KX_SOFT_RESET_TOTAL_WAIT_TIME_US);
 	if (ret) {
 		dev_err(data->dev, "Sensor reset %s\n",
-			val & KX022A_MASK_SRST ? "timeout" : "fail#");
+			val & KX_MASK_SRST ? "timeout" : "fail#");
 		return ret;
 	}
 
-	ret = regmap_reinit_cache(data->regmap, &kx022a_regmap);
+	ret = regmap_reinit_cache(data->regmap, data->chip_info->regmap_config);
 	if (ret) {
 		dev_err(data->dev, "Failed to reinit reg cache\n");
 		return ret;
 	}
 
 	/* set data res 16bit */
-	ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
-			      KX022A_MASK_BRES16);
+	ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
+			      KX_MASK_BRES16);
 	if (ret) {
 		dev_err(data->dev, "Failed to set data resolution\n");
 		return ret;
@@ -996,7 +976,7 @@  static int kx022a_chip_init(struct kx022a_data *data)
 	return kx022a_prepare_irq_pin(data);
 }
 
-int kx022a_probe_internal(struct device *dev)
+int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)
 {
 	static const char * const regulator_names[] = {"io-vdd", "vdd"};
 	struct iio_trigger *indio_trig;
@@ -1023,6 +1003,7 @@  int kx022a_probe_internal(struct device *dev)
 		return -ENOMEM;
 
 	data = iio_priv(idev);
+	data->chip_info = chip_info;
 
 	/*
 	 * VDD is the analog and digital domain voltage supply and
@@ -1033,37 +1014,37 @@  int kx022a_probe_internal(struct device *dev)
 	if (ret && ret != -ENODEV)
 		return dev_err_probe(dev, ret, "failed to enable regulator\n");
 
-	ret = regmap_read(regmap, KX022A_REG_WHO, &chip_id);
+	ret = regmap_read(regmap, data->chip_info->who, &chip_id);
 	if (ret)
 		return dev_err_probe(dev, ret, "Failed to access sensor\n");
 
-	if (chip_id != KX022A_ID) {
+	if (chip_id != data->chip_info->id) {
 		dev_err(dev, "unsupported device 0x%x\n", chip_id);
 		return -EINVAL;
 	}
 
 	irq = fwnode_irq_get_byname(fwnode, "INT1");
 	if (irq > 0) {
-		data->inc_reg = KX022A_REG_INC1;
-		data->ien_reg = KX022A_REG_INC4;
+		data->inc_reg = data->chip_info->inc1;
+		data->ien_reg = data->chip_info->inc4;
 	} else {
 		irq = fwnode_irq_get_byname(fwnode, "INT2");
 		if (irq <= 0)
 			return dev_err_probe(dev, irq, "No suitable IRQ\n");
 
-		data->inc_reg = KX022A_REG_INC5;
-		data->ien_reg = KX022A_REG_INC6;
+		data->inc_reg = data->chip_info->inc5;
+		data->ien_reg = data->chip_info->inc6;
 	}
 
 	data->regmap = regmap;
 	data->dev = dev;
 	data->irq = irq;
-	data->odr_ns = KX022A_DEFAULT_PERIOD_NS;
+	data->odr_ns = KX_DEFAULT_PERIOD_NS;
 	mutex_init(&data->mutex);
 
-	idev->channels = kx022a_channels;
-	idev->num_channels = ARRAY_SIZE(kx022a_channels);
-	idev->name = "kx022-accel";
+	idev->channels = data->chip_info->channels;
+	idev->num_channels = data->chip_info->num_channels;
+	idev->name = data->chip_info->name;
 	idev->info = &kx022a_info;
 	idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
 	idev->available_scan_masks = kx022a_scan_masks;
@@ -1112,7 +1093,7 @@  int kx022a_probe_internal(struct device *dev)
 	 * No need to check for NULL. request_threaded_irq() defaults to
 	 * dev_name() should the alloc fail.
 	 */
-	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-kx022a",
+	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-accel",
 			      dev_name(data->dev));
 
 	ret = devm_request_threaded_irq(data->dev, irq, kx022a_irq_handler,
diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h
index 12424649d438..3bb40e9f5613 100644
--- a/drivers/iio/accel/kionix-kx022a.h
+++ b/drivers/iio/accel/kionix-kx022a.h
@@ -11,24 +11,48 @@ 
 #include <linux/bits.h>
 #include <linux/regmap.h>
 
+#include <linux/iio/iio.h>
+
+/* Common for all supported devices */
+#define KX_FIFO_SAMPLES_SIZE_BYTES	    6
+#define KX_SOFT_RESET_WAIT_TIME_US	    (5 * USEC_PER_MSEC)
+#define KX_SOFT_RESET_TOTAL_WAIT_TIME_US    (500 * USEC_PER_MSEC)
+#define KX_DEFAULT_PERIOD_NS		    (20 * NSEC_PER_MSEC)
+#define KX_MASK_GSEL			    GENMASK(4, 3)
+#define KX_MASK_ODR			    GENMASK(3, 0)
+#define KX_MASK_WM_TH			    GENMASK(6, 0)
+#define KX_GSEL_SHIFT			    3
+#define KX_MASK_IEN			    BIT(5)
+#define KX_MASK_DRDY			    BIT(5)
+#define KX_MASK_PC1			    BIT(7)
+#define KX_MASK_IPOL			    BIT(4)
+#define KX_IPOL_LOW			    0
+#define KX_MASK_ITYP			    BIT(3)
+#define KX_ITYP_LEVEL			    0
+#define KX_MASK_INS2_DRDY		    BIT(4)
+#define KX_MASK_WMI			    BIT(5)
+#define KX_MASK_BUF_EN			    BIT(7)
+#define KX_MASK_SRST			    BIT(7)
+#define KX_MASK_BRES16			    BIT(6)
+
+
 #define KX022A_REG_WHO		0x0f
 #define KX022A_ID		0xc8
 
+#define KX022A_FIFO_LENGTH	43
+#define KX022A_FIFO_FULL_VALUE	255
+#define KX022A_FIFO_MAX_BYTES					\
+	 (KX022A_FIFO_LENGTH * KX_FIFO_SAMPLES_SIZE_BYTES)
+
 #define KX022A_REG_CNTL2	0x19
-#define KX022A_MASK_SRST	BIT(7)
 #define KX022A_REG_CNTL		0x18
-#define KX022A_MASK_PC1		BIT(7)
 #define KX022A_MASK_RES		BIT(6)
-#define KX022A_MASK_DRDY	BIT(5)
-#define KX022A_MASK_GSEL	GENMASK(4, 3)
-#define KX022A_GSEL_SHIFT	3
 #define KX022A_GSEL_2		0x0
 #define KX022A_GSEL_4		BIT(3)
 #define KX022A_GSEL_8		BIT(4)
 #define KX022A_GSEL_16		GENMASK(4, 3)
 
 #define KX022A_REG_INS2		0x13
-#define KX022A_MASK_INS2_DRDY	BIT(4)
 #define KX122_MASK_INS2_WMI	BIT(5)
 
 #define KX022A_REG_XHP_L	0x0
@@ -45,38 +69,104 @@ 
 #define KX022A_REG_MAN_WAKE	0x2c
 
 #define KX022A_REG_BUF_CNTL1	0x3a
-#define KX022A_MASK_WM_TH	GENMASK(6, 0)
 #define KX022A_REG_BUF_CNTL2	0x3b
-#define KX022A_MASK_BUF_EN	BIT(7)
-#define KX022A_MASK_BRES16	BIT(6)
 #define KX022A_REG_BUF_STATUS_1	0x3c
 #define KX022A_REG_BUF_STATUS_2	0x3d
+#define KX022A_MASK_BUF_SMP_LVL GENMASK(6, 0)
 #define KX022A_REG_BUF_CLEAR	0x3e
 #define KX022A_REG_BUF_READ	0x3f
-#define KX022A_MASK_ODR		GENMASK(3, 0)
 #define KX022A_ODR_SHIFT	3
 #define KX022A_FIFO_MAX_WMI_TH	41
 
 #define KX022A_REG_INC1		0x1c
 #define KX022A_REG_INC5		0x20
 #define KX022A_REG_INC6		0x21
-#define KX022A_MASK_IEN		BIT(5)
-#define KX022A_MASK_IPOL	BIT(4)
 #define KX022A_IPOL_LOW		0
-#define KX022A_IPOL_HIGH	KX022A_MASK_IPOL1
-#define KX022A_MASK_ITYP	BIT(3)
-#define KX022A_ITYP_PULSE	KX022A_MASK_ITYP
-#define KX022A_ITYP_LEVEL	0
+#define KX022A_IPOL_HIGH	KX_MASK_IPOL
+#define KX022A_ITYP_PULSE	KX_MASK_ITYP
 
 #define KX022A_REG_INC4		0x1f
-#define KX022A_MASK_WMI		BIT(5)
 
 #define KX022A_REG_SELF_TEST	0x60
 #define KX022A_MAX_REGISTER	0x60
 
+enum kx022a_device_type {
+	KX022A,
+};
+
+enum {
+	KX_STATE_SAMPLE,
+	KX_STATE_FIFO,
+};
+
+enum {
+	AXIS_X,
+	AXIS_Y,
+	AXIS_Z,
+	AXIS_MAX
+};
+
 struct device;
 
-int kx022a_probe_internal(struct device *dev);
-extern const struct regmap_config kx022a_regmap;
+struct kx022a_chip_info {
+	const char *name;
+	enum kx022a_device_type type;
+	const struct regmap_config *regmap_config;
+	const struct iio_chan_spec *channels;
+	unsigned int num_channels;
+	unsigned int fifo_length;
+	u8 who;
+	u8 id;
+	u8 cntl;
+	u8 cntl2;
+	u8 odcntl;
+	u8 buf_cntl1;
+	u8 buf_cntl2;
+	u8 buf_clear;
+	u8 buf_status1;
+	u16 buf_smp_lvl_mask;
+	u8 buf_read;
+	u8 inc1;
+	u8 inc4;
+	u8 inc5;
+	u8 inc6;
+	u8 xout_l;
+};
+
+struct kx022a_data {
+	const struct kx022a_chip_info *chip_info;
+	struct regmap *regmap;
+	struct iio_trigger *trig;
+	struct device *dev;
+	struct iio_mount_matrix orientation;
+	int64_t timestamp, old_timestamp;
+
+	int irq;
+	int inc_reg;
+	int ien_reg;
+
+	unsigned int state;
+	unsigned int odr_ns;
+
+	bool trigger_enabled;
+	/*
+	 * Prevent toggling the sensor stby/active state (PC1 bit) in the
+	 * middle of a configuration, or when the fifo is enabled. Also,
+	 * protect the data stored/retrieved from this structure from
+	 * concurrent accesses.
+	 */
+	struct mutex mutex;
+	u8 watermark;
+
+	/* 3 x 16bit accel data + timestamp */
+	__le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
+};
+
+int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info);
+extern const struct kx022a_chip_info kx_chip_info[];
 
 #endif