diff mbox series

[4/4] hwmon: vcnl3020: add hwmon driver for intrusion sensor

Message ID 20210430152419.261757-5-i.mikhaylov@yadro.com (mailing list archive)
State Superseded, archived
Headers show
Series add periodic mode, threshold options and hwmon | expand

Commit Message

Ivan Mikhaylov April 30, 2021, 3:24 p.m. UTC
Intrusion status detection via Interrupt Status Register.

Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
---
 drivers/hwmon/Kconfig                  |  7 +++
 drivers/hwmon/Makefile                 |  1 +
 drivers/hwmon/vcnl3020-hwmon.c         | 57 ++++++++++++++++++++++
 drivers/iio/proximity/vcnl3020.c       | 67 ++++++++++++++++++++------
 include/linux/iio/proximity/vcnl3020.h | 26 ++++++++++
 5 files changed, 143 insertions(+), 15 deletions(-)
 create mode 100644 drivers/hwmon/vcnl3020-hwmon.c
 create mode 100644 include/linux/iio/proximity/vcnl3020.h

Comments

Guenter Roeck April 30, 2021, 4:38 p.m. UTC | #1
On Fri, Apr 30, 2021 at 06:24:19PM +0300, Ivan Mikhaylov wrote:
> Intrusion status detection via Interrupt Status Register.
> 
> Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>

I think this should, if at all, be handled using the
iio->hwmon bridge (or, in other words, require a solution
which is not chip specific).

I am also not sure if "proximity" is really appropriate to use
for intrusion detection in the sense of hardware monitoring.
This would require a proximity sensor within a chassis, which
would be both overkill and unlikely to happen in the real world.
"Intrusion", in hardware monitoring context, means "someone
opened the chassis", not "someone got [too] close".

> ---
>  drivers/hwmon/Kconfig                  |  7 +++
>  drivers/hwmon/Makefile                 |  1 +
>  drivers/hwmon/vcnl3020-hwmon.c         | 57 ++++++++++++++++++++++
>  drivers/iio/proximity/vcnl3020.c       | 67 ++++++++++++++++++++------
>  include/linux/iio/proximity/vcnl3020.h | 26 ++++++++++
>  5 files changed, 143 insertions(+), 15 deletions(-)
>  create mode 100644 drivers/hwmon/vcnl3020-hwmon.c
>  create mode 100644 include/linux/iio/proximity/vcnl3020.h
> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 1ecf697d8d99..862205bbb3bf 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -1916,6 +1916,13 @@ config SENSORS_TMP513
>  	  This driver can also be built as a module. If so, the module
>  	  will be called tmp513.
>  
> +config SENSORS_VCNL3020
> +	tristate "VCNL3020"
> +	depends on I2C && VCNL3020
> +	help
> +	  If you say yes here you get support for the intrusion
> +	  sensor via VCNL3020 proximity sensor.
> +
>  config SENSORS_VEXPRESS
>  	tristate "Versatile Express"
>  	depends on VEXPRESS_CONFIG
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 09a86c5e1d29..1d96212587aa 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -186,6 +186,7 @@ obj-$(CONFIG_SENSORS_TMP108)	+= tmp108.o
>  obj-$(CONFIG_SENSORS_TMP401)	+= tmp401.o
>  obj-$(CONFIG_SENSORS_TMP421)	+= tmp421.o
>  obj-$(CONFIG_SENSORS_TMP513)	+= tmp513.o
> +obj-$(CONFIG_SENSORS_VCNL3020)	+= vcnl3020-hwmon.o
>  obj-$(CONFIG_SENSORS_VEXPRESS)	+= vexpress-hwmon.o
>  obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
>  obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
> diff --git a/drivers/hwmon/vcnl3020-hwmon.c b/drivers/hwmon/vcnl3020-hwmon.c
> new file mode 100644
> index 000000000000..199bea25723b
> --- /dev/null
> +++ b/drivers/hwmon/vcnl3020-hwmon.c
> @@ -0,0 +1,57 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * vcnl3020-hwmon.c - intrusion sensor.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/device.h>
> +#include <linux/platform_device.h>
> +#include <linux/iio/proximity/vcnl3020.h>
> +
> +static ssize_t vcnl3020_show(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct vcnl3020_data *vcnl3020_data = dev_get_drvdata(dev);
> +
> +	bool data = vcnl3020_is_thr_triggered(vcnl3020_data);
> +
> +	return sprintf(buf, "%u\n", data);
> +}
> +
> +static SENSOR_DEVICE_ATTR_2_RO(intrusion0_alarm, vcnl3020, 0, 0);
> +
> +static struct attribute *vcnl3020_attrs[] = {
> +	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
> +	NULL
> +};
> +ATTRIBUTE_GROUPS(vcnl3020);
> +
> +static int32_t vcnl3020_hwmon_probe(struct platform_device *pdev)
> +{
> +	struct vcnl3020_data *vcnl3020_data = platform_get_drvdata(pdev);
> +	struct device *hwmon_dev;
> +
> +	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
> +							   VCNL3020_DRV,
> +							   vcnl3020_data,
> +							   vcnl3020_groups);

Please note that new drivers must register using
[devm_]hwmon_device_register_with_info().

Thanks,
Guenter

> +	return PTR_ERR_OR_ZERO(hwmon_dev);
> +}
> +
> +static struct platform_driver vcnl3020_hwmon_driver = {
> +	.probe = vcnl3020_hwmon_probe,
> +	.driver = {
> +		.name = VCNL3020_DRV_HWMON,
> +	},
> +};
> +
> +module_platform_driver(vcnl3020_hwmon_driver);
> +
> +MODULE_AUTHOR("Ivan Mikhaylov <i.mikhaylov@yadro.com>");
> +MODULE_DESCRIPTION("Intrusion sensor for VCNL3020");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c
> index bff59c7af966..67baa14cc900 100644
> --- a/drivers/iio/proximity/vcnl3020.c
> +++ b/drivers/iio/proximity/vcnl3020.c
> @@ -11,9 +11,11 @@
>  #include <linux/err.h>
>  #include <linux/delay.h>
>  #include <linux/regmap.h>
> +#include <linux/platform_device.h>
>  
>  #include <linux/iio/iio.h>
>  #include <linux/iio/sysfs.h>
> +#include <linux/iio/proximity/vcnl3020.h>
>  
>  #define VCNL3020_PROD_ID	0x21
>  
> @@ -66,18 +68,6 @@ static const int vcnl3020_prox_sampling_frequency[][2] = {
>  	{250, 0},
>  };
>  
> -/**
> - * struct vcnl3020_data - vcnl3020 specific data.
> - * @regmap:	device register map.
> - * @dev:	vcnl3020 device.
> - * @rev:	revision id.
> - */
> -struct vcnl3020_data {
> -	struct regmap *regmap;
> -	struct device *dev;
> -	u8 rev;
> -};
> -
>  /**
>   * struct vcnl3020_property - vcnl3020 property.
>   * @name:	property name.
> @@ -330,6 +320,23 @@ static int vcnl3020_write_event(struct iio_dev *indio_dev,
>  	return rc;
>  }
>  
> +#ifdef CONFIG_SENSORS_VCNL3020
> +
> +bool vcnl3020_is_thr_triggered(struct vcnl3020_data *data)
> +{
> +	int rc;
> +	unsigned int isr;
> +
> +	rc = regmap_read(data->regmap, VCNL_ISR, &isr);
> +	if (rc)
> +		return false;
> +
> +	return !!((isr & VCNL_INT_TH_LOW) || (isr & VCNL_INT_TH_HI));
> +}
> +EXPORT_SYMBOL_GPL(vcnl3020_is_thr_triggered);
> +
> +#endif
> +
>  static int vcnl3020_config_threshold(struct iio_dev *indio_dev, bool state)
>  {
>  	struct vcnl3020_data *data = iio_priv(indio_dev);
> @@ -536,6 +543,7 @@ static int vcnl3020_probe(struct i2c_client *client)
>  	struct vcnl3020_data *data;
>  	struct iio_dev *indio_dev;
>  	struct regmap *regmap;
> +	struct platform_device *pdev;
>  	int rc;
>  
>  	regmap = devm_regmap_init_i2c(client, &vcnl3020_regmap_config);
> @@ -560,10 +568,39 @@ static int vcnl3020_probe(struct i2c_client *client)
>  	indio_dev->info = &vcnl3020_info;
>  	indio_dev->channels = vcnl3020_channels;
>  	indio_dev->num_channels = ARRAY_SIZE(vcnl3020_channels);
> -	indio_dev->name = "vcnl3020";
> +	indio_dev->name = VCNL3020_DRV;
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  
> -	return devm_iio_device_register(&client->dev, indio_dev);
> +	rc = devm_iio_device_register(&client->dev, indio_dev);
> +	if (rc != 0)
> +		goto err_out;
> +
> +#ifdef CONFIG_SENSORS_VCNL3020
> +
> +	pdev = platform_device_alloc(VCNL3020_DRV_HWMON, -1);
> +	if (!pdev) {
> +		dev_err(&client->dev, "Failed to allocate %s\n",
> +			VCNL3020_DRV_HWMON);
> +		rc = -ENOMEM;
> +		goto err_out;
> +	}
> +
> +	pdev->dev.parent = &indio_dev->dev;
> +	platform_set_drvdata(pdev, data);
> +	rc = platform_device_add(pdev);
> +	if (rc != 0) {
> +		dev_err(&client->dev, "Failed to register %s: %d\n",
> +			VCNL3020_DRV_HWMON, rc);
> +		platform_device_put(pdev);
> +		pdev = NULL;
> +		goto err_out;
> +	}
> +
> +#endif
> +
> +err_out:
> +
> +	return rc;
>  }
>  
>  static const struct of_device_id vcnl3020_of_match[] = {
> @@ -576,7 +613,7 @@ MODULE_DEVICE_TABLE(of, vcnl3020_of_match);
>  
>  static struct i2c_driver vcnl3020_driver = {
>  	.driver = {
> -		.name   = "vcnl3020",
> +		.name   = VCNL3020_DRV,
>  		.of_match_table = vcnl3020_of_match,
>  	},
>  	.probe_new  = vcnl3020_probe,
> diff --git a/include/linux/iio/proximity/vcnl3020.h b/include/linux/iio/proximity/vcnl3020.h
> new file mode 100644
> index 000000000000..d99783298e6e
> --- /dev/null
> +++ b/include/linux/iio/proximity/vcnl3020.h
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * This file describe API for VCNL3020 proximity sensor.
> + */
> +
> +#ifndef VCNL3020_PROXIMITY_H
> +#define VCNL3020_PROXIMITY_H
> +
> +#define VCNL3020_DRV_HWMON	"vcnl3020-hwmon"
> +#define VCNL3020_DRV		"vcnl3020"
> +
> +/**
> + * struct vcnl3020_data - vcnl3020 specific data.
> + * @regmap:	device register map.
> + * @dev:	vcnl3020 device.
> + * @rev:	revision id.
> + */
> +struct vcnl3020_data {
> +	struct regmap *regmap;
> +	struct device *dev;
> +	u8 rev;
> +};
> +
> +bool vcnl3020_is_thr_triggered(struct vcnl3020_data *data);
> +
> +#endif
> -- 
> 2.26.3
>
kernel test robot May 1, 2021, 7:07 a.m. UTC | #2
Hi Ivan,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on iio/togreg]
[also build test ERROR on next-20210430]
[cannot apply to hwmon/hwmon-next v5.12]
[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]

url:    https://github.com/0day-ci/linux/commits/Ivan-Mikhaylov/add-periodic-mode-threshold-options-and-hwmon/20210430-231929
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 9.3.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/0day-ci/linux/commit/6c71dd96a8b45aa67f6ad388b5e67269f02b854c
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Ivan-Mikhaylov/add-periodic-mode-threshold-options-and-hwmon/20210430-231929
        git checkout 6c71dd96a8b45aa67f6ad388b5e67269f02b854c
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross W=1 ARCH=sh 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

ERROR: modpost: "remap_vmalloc_range_partial" [samples/vfio-mdev/mdpy.ko] undefined!
>> ERROR: modpost: "vcnl3020_is_thr_triggered" [drivers/hwmon/vcnl3020-hwmon.ko] undefined!
ERROR: modpost: "__delay" [drivers/net/mdio/mdio-cavium.ko] undefined!
ERROR: modpost: "__udivdi3" [fs/btrfs/btrfs.ko] undefined!
ERROR: modpost: "__umoddi3" [fs/btrfs/btrfs.ko] undefined!

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for SND_ATMEL_SOC_PDC
   Depends on SOUND && !UML && SND && SND_SOC && SND_ATMEL_SOC && HAS_DMA
   Selected by
   - SND_ATMEL_SOC_SSC && SOUND && !UML && SND && SND_SOC && SND_ATMEL_SOC
   - SND_ATMEL_SOC_SSC_PDC && SOUND && !UML && SND && SND_SOC && SND_ATMEL_SOC && ATMEL_SSC

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Ivan Mikhaylov May 4, 2021, 7:46 p.m. UTC | #3
On Fri, 2021-04-30 at 09:38 -0700, Guenter Roeck wrote:
> On Fri, Apr 30, 2021 at 06:24:19PM +0300, Ivan Mikhaylov wrote:
> > Intrusion status detection via Interrupt Status Register.
> > 
> > Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
> 
> I think this should, if at all, be handled using the
> iio->hwmon bridge (or, in other words, require a solution
> which is not chip specific).

Thanks a lot for suggestion, it's actually looks what's needed here instead of
this driver. Anyways, there is no IIO_PROXIMITY support inside supported types
in iio_hwmon.c. Should I add additional case inside this driver for
IIO_PROXIMITY type?

> I am also not sure if "proximity" is really appropriate to use
> for intrusion detection in the sense of hardware monitoring.
> This would require a proximity sensor within a chassis, which
> would be both overkill and unlikely to happen in the real world.
> "Intrusion", in hardware monitoring context, means "someone
> opened the chassis", not "someone got [too] close".
> 

I'm not sure either but it exists :) And it's exactly for this purpose:
"someone opened the chassis", "how near/far is cover?".
Jonathan Cameron May 5, 2021, 8:26 a.m. UTC | #4
On Tue, 4 May 2021 22:46:53 +0300
Ivan Mikhaylov <i.mikhaylov@yadro.com> wrote:

> On Fri, 2021-04-30 at 09:38 -0700, Guenter Roeck wrote:
> > On Fri, Apr 30, 2021 at 06:24:19PM +0300, Ivan Mikhaylov wrote:  
> > > Intrusion status detection via Interrupt Status Register.
> > > 
> > > Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>  
> > 
> > I think this should, if at all, be handled using the
> > iio->hwmon bridge (or, in other words, require a solution
> > which is not chip specific).  
> 
> Thanks a lot for suggestion, it's actually looks what's needed here instead of
> this driver. Anyways, there is no IIO_PROXIMITY support inside supported types
> in iio_hwmon.c. Should I add additional case inside this driver for
> IIO_PROXIMITY type?
> 
> > I am also not sure if "proximity" is really appropriate to use
> > for intrusion detection in the sense of hardware monitoring.
> > This would require a proximity sensor within a chassis, which
> > would be both overkill and unlikely to happen in the real world.
> > "Intrusion", in hardware monitoring context, means "someone
> > opened the chassis", not "someone got [too] close".
> >   
> 
> I'm not sure either but it exists :) And it's exactly for this purpose:
> "someone opened the chassis", "how near/far is cover?".
> 

Hmm. So we will have somewhat of an impedance mismatch.

In IIO events are push based (typically interrupt driven).
There is also the issue that we don't currently have in kernel
interfaces to allow drivers like iio-hwmon to use them (there
has never been enough demand though it has been discussed a few
times).   As such we'd need to implement the core support for
that as well.   We might get away with some simplifications that
make this not too painful - e.g. avoid the need to filter events
by stating that a consumer may well get events it's not interested
in and it is up to the consumer to check (a later optimization could
then add filtering similar to what we do for main data flows).

Jonathan
Guenter Roeck May 5, 2021, 2:02 p.m. UTC | #5
On Tue, May 04, 2021 at 10:46:53PM +0300, Ivan Mikhaylov wrote:
> On Fri, 2021-04-30 at 09:38 -0700, Guenter Roeck wrote:
> > On Fri, Apr 30, 2021 at 06:24:19PM +0300, Ivan Mikhaylov wrote:
> > > Intrusion status detection via Interrupt Status Register.
> > > 
> > > Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
> > 
> > I think this should, if at all, be handled using the
> > iio->hwmon bridge (or, in other words, require a solution
> > which is not chip specific).
> 
> Thanks a lot for suggestion, it's actually looks what's needed here instead of
> this driver. Anyways, there is no IIO_PROXIMITY support inside supported types
> in iio_hwmon.c. Should I add additional case inside this driver for
> IIO_PROXIMITY type?
> 
> > I am also not sure if "proximity" is really appropriate to use
> > for intrusion detection in the sense of hardware monitoring.
> > This would require a proximity sensor within a chassis, which
> > would be both overkill and unlikely to happen in the real world.
> > "Intrusion", in hardware monitoring context, means "someone
> > opened the chassis", not "someone got [too] close".
> > 
> 
> I'm not sure either but it exists :) And it's exactly for this purpose:
> "someone opened the chassis", "how near/far is cover?".
> 

The cost for VCNL3020, for a full reel with 3,300 chips, is $1.17 per chip
at Mouser. A mechanical switch costs a couple of cents. A single proximity
sensor won't cover all parts of a chassis; one would likely need several
chips to be sure that are no blind spots (if that is even possible - I don't
think it is in any of my PC chassis due to mechanical limitations). This
is on top of programming, which would be sensitive to generating false
alarms (or missing alarms, for that matter). That sounds quite impractical
and expensive to me. I'd really like to see the actual use case where a
proximity sensor (or set of proximity sensors) is used for intrusion
detection in the sense of hardware monitoring - not just the technical
possibility of doing so, but an actual use case (as in "this vendor,
in this chassis, is doing it").

Thanks,
Guenter
Ivan Mikhaylov May 17, 2021, 5:08 p.m. UTC | #6
On Wed, 2021-05-05 at 07:02 -0700, Guenter Roeck wrote:
> On Tue, May 04, 2021 at 10:46:53PM +0300, Ivan Mikhaylov wrote:
> > On Fri, 2021-04-30 at 09:38 -0700, Guenter Roeck wrote:
> > > On Fri, Apr 30, 2021 at 06:24:19PM +0300, Ivan Mikhaylov wrote:
> > > > Intrusion status detection via Interrupt Status Register.
> > > > 
> > > > Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
> > > 
> > > I think this should, if at all, be handled using the
> > > iio->hwmon bridge (or, in other words, require a solution
> > > which is not chip specific).
> > 
> > Thanks a lot for suggestion, it's actually looks what's needed here instead
> > of
> > this driver. Anyways, there is no IIO_PROXIMITY support inside supported
> > types
> > in iio_hwmon.c. Should I add additional case inside this driver for
> > IIO_PROXIMITY type?
> > 
> > > I am also not sure if "proximity" is really appropriate to use
> > > for intrusion detection in the sense of hardware monitoring.
> > > This would require a proximity sensor within a chassis, which
> > > would be both overkill and unlikely to happen in the real world.
> > > "Intrusion", in hardware monitoring context, means "someone
> > > opened the chassis", not "someone got [too] close".
> > > 
> > 
> > I'm not sure either but it exists :) And it's exactly for this purpose:
> > "someone opened the chassis", "how near/far is cover?".
> > 
> 
> The cost for VCNL3020, for a full reel with 3,300 chips, is $1.17 per chip
> at Mouser. A mechanical switch costs a couple of cents. A single proximity
> sensor won't cover all parts of a chassis; one would likely need several
> chips to be sure that are no blind spots (if that is even possible - I don't
> think it is in any of my PC chassis due to mechanical limitations). This
> is on top of programming, which would be sensitive to generating false
> alarms (or missing alarms, for that matter). That sounds quite impractical
> and expensive to me. I'd really like to see the actual use case where a
> proximity sensor (or set of proximity sensors) is used for intrusion
> detection in the sense of hardware monitoring - not just the technical
> possibility of doing so, but an actual use case (as in "this vendor,
> in this chassis, is doing it").
> 
> Thanks,
> Guenter


Guenter, VCNL3020 is indeed used as an intrusion detection sensor at least in
one real design. That is YADRO VESNIN Rev. C where the proximity sensor is
installed in a very tight space on an nvme switch board where installation of a
mechanical switch was not possible without substantial redesign of the existing
other components that would cost a lot more than the price of VCNL3020.

VESNIN is a very tight-packed design of 4 x POWER8 CPUs, up to 8TB of RAM, and 26 nvme disks, all that in just 2U.
* https://imgur.com/a/wU9wEd4
diff mbox series

Patch

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 1ecf697d8d99..862205bbb3bf 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1916,6 +1916,13 @@  config SENSORS_TMP513
 	  This driver can also be built as a module. If so, the module
 	  will be called tmp513.
 
+config SENSORS_VCNL3020
+	tristate "VCNL3020"
+	depends on I2C && VCNL3020
+	help
+	  If you say yes here you get support for the intrusion
+	  sensor via VCNL3020 proximity sensor.
+
 config SENSORS_VEXPRESS
 	tristate "Versatile Express"
 	depends on VEXPRESS_CONFIG
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 09a86c5e1d29..1d96212587aa 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -186,6 +186,7 @@  obj-$(CONFIG_SENSORS_TMP108)	+= tmp108.o
 obj-$(CONFIG_SENSORS_TMP401)	+= tmp401.o
 obj-$(CONFIG_SENSORS_TMP421)	+= tmp421.o
 obj-$(CONFIG_SENSORS_TMP513)	+= tmp513.o
+obj-$(CONFIG_SENSORS_VCNL3020)	+= vcnl3020-hwmon.o
 obj-$(CONFIG_SENSORS_VEXPRESS)	+= vexpress-hwmon.o
 obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
diff --git a/drivers/hwmon/vcnl3020-hwmon.c b/drivers/hwmon/vcnl3020-hwmon.c
new file mode 100644
index 000000000000..199bea25723b
--- /dev/null
+++ b/drivers/hwmon/vcnl3020-hwmon.c
@@ -0,0 +1,57 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vcnl3020-hwmon.c - intrusion sensor.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/iio/proximity/vcnl3020.h>
+
+static ssize_t vcnl3020_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct vcnl3020_data *vcnl3020_data = dev_get_drvdata(dev);
+
+	bool data = vcnl3020_is_thr_triggered(vcnl3020_data);
+
+	return sprintf(buf, "%u\n", data);
+}
+
+static SENSOR_DEVICE_ATTR_2_RO(intrusion0_alarm, vcnl3020, 0, 0);
+
+static struct attribute *vcnl3020_attrs[] = {
+	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(vcnl3020);
+
+static int32_t vcnl3020_hwmon_probe(struct platform_device *pdev)
+{
+	struct vcnl3020_data *vcnl3020_data = platform_get_drvdata(pdev);
+	struct device *hwmon_dev;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
+							   VCNL3020_DRV,
+							   vcnl3020_data,
+							   vcnl3020_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct platform_driver vcnl3020_hwmon_driver = {
+	.probe = vcnl3020_hwmon_probe,
+	.driver = {
+		.name = VCNL3020_DRV_HWMON,
+	},
+};
+
+module_platform_driver(vcnl3020_hwmon_driver);
+
+MODULE_AUTHOR("Ivan Mikhaylov <i.mikhaylov@yadro.com>");
+MODULE_DESCRIPTION("Intrusion sensor for VCNL3020");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c
index bff59c7af966..67baa14cc900 100644
--- a/drivers/iio/proximity/vcnl3020.c
+++ b/drivers/iio/proximity/vcnl3020.c
@@ -11,9 +11,11 @@ 
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/regmap.h>
+#include <linux/platform_device.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/proximity/vcnl3020.h>
 
 #define VCNL3020_PROD_ID	0x21
 
@@ -66,18 +68,6 @@  static const int vcnl3020_prox_sampling_frequency[][2] = {
 	{250, 0},
 };
 
-/**
- * struct vcnl3020_data - vcnl3020 specific data.
- * @regmap:	device register map.
- * @dev:	vcnl3020 device.
- * @rev:	revision id.
- */
-struct vcnl3020_data {
-	struct regmap *regmap;
-	struct device *dev;
-	u8 rev;
-};
-
 /**
  * struct vcnl3020_property - vcnl3020 property.
  * @name:	property name.
@@ -330,6 +320,23 @@  static int vcnl3020_write_event(struct iio_dev *indio_dev,
 	return rc;
 }
 
+#ifdef CONFIG_SENSORS_VCNL3020
+
+bool vcnl3020_is_thr_triggered(struct vcnl3020_data *data)
+{
+	int rc;
+	unsigned int isr;
+
+	rc = regmap_read(data->regmap, VCNL_ISR, &isr);
+	if (rc)
+		return false;
+
+	return !!((isr & VCNL_INT_TH_LOW) || (isr & VCNL_INT_TH_HI));
+}
+EXPORT_SYMBOL_GPL(vcnl3020_is_thr_triggered);
+
+#endif
+
 static int vcnl3020_config_threshold(struct iio_dev *indio_dev, bool state)
 {
 	struct vcnl3020_data *data = iio_priv(indio_dev);
@@ -536,6 +543,7 @@  static int vcnl3020_probe(struct i2c_client *client)
 	struct vcnl3020_data *data;
 	struct iio_dev *indio_dev;
 	struct regmap *regmap;
+	struct platform_device *pdev;
 	int rc;
 
 	regmap = devm_regmap_init_i2c(client, &vcnl3020_regmap_config);
@@ -560,10 +568,39 @@  static int vcnl3020_probe(struct i2c_client *client)
 	indio_dev->info = &vcnl3020_info;
 	indio_dev->channels = vcnl3020_channels;
 	indio_dev->num_channels = ARRAY_SIZE(vcnl3020_channels);
-	indio_dev->name = "vcnl3020";
+	indio_dev->name = VCNL3020_DRV;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
-	return devm_iio_device_register(&client->dev, indio_dev);
+	rc = devm_iio_device_register(&client->dev, indio_dev);
+	if (rc != 0)
+		goto err_out;
+
+#ifdef CONFIG_SENSORS_VCNL3020
+
+	pdev = platform_device_alloc(VCNL3020_DRV_HWMON, -1);
+	if (!pdev) {
+		dev_err(&client->dev, "Failed to allocate %s\n",
+			VCNL3020_DRV_HWMON);
+		rc = -ENOMEM;
+		goto err_out;
+	}
+
+	pdev->dev.parent = &indio_dev->dev;
+	platform_set_drvdata(pdev, data);
+	rc = platform_device_add(pdev);
+	if (rc != 0) {
+		dev_err(&client->dev, "Failed to register %s: %d\n",
+			VCNL3020_DRV_HWMON, rc);
+		platform_device_put(pdev);
+		pdev = NULL;
+		goto err_out;
+	}
+
+#endif
+
+err_out:
+
+	return rc;
 }
 
 static const struct of_device_id vcnl3020_of_match[] = {
@@ -576,7 +613,7 @@  MODULE_DEVICE_TABLE(of, vcnl3020_of_match);
 
 static struct i2c_driver vcnl3020_driver = {
 	.driver = {
-		.name   = "vcnl3020",
+		.name   = VCNL3020_DRV,
 		.of_match_table = vcnl3020_of_match,
 	},
 	.probe_new  = vcnl3020_probe,
diff --git a/include/linux/iio/proximity/vcnl3020.h b/include/linux/iio/proximity/vcnl3020.h
new file mode 100644
index 000000000000..d99783298e6e
--- /dev/null
+++ b/include/linux/iio/proximity/vcnl3020.h
@@ -0,0 +1,26 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file describe API for VCNL3020 proximity sensor.
+ */
+
+#ifndef VCNL3020_PROXIMITY_H
+#define VCNL3020_PROXIMITY_H
+
+#define VCNL3020_DRV_HWMON	"vcnl3020-hwmon"
+#define VCNL3020_DRV		"vcnl3020"
+
+/**
+ * struct vcnl3020_data - vcnl3020 specific data.
+ * @regmap:	device register map.
+ * @dev:	vcnl3020 device.
+ * @rev:	revision id.
+ */
+struct vcnl3020_data {
+	struct regmap *regmap;
+	struct device *dev;
+	u8 rev;
+};
+
+bool vcnl3020_is_thr_triggered(struct vcnl3020_data *data);
+
+#endif