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

Ivan Mikhaylov
2021-04-30T15:16:21Z

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

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
--
2.26.3