samples: sensor: Add VCNL4040 sample

Add sample to show usage of VCNL4040 sensor driver

Signed-off-by: Richard Osterloh <richard.osterloh@gmail.com>
diff --git a/samples/sensor/vcnl4040/CMakeLists.txt b/samples/sensor/vcnl4040/CMakeLists.txt
new file mode 100644
index 0000000..c6e9520
--- /dev/null
+++ b/samples/sensor/vcnl4040/CMakeLists.txt
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.13.1)
+find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
+project(vcnl4040)
+
+target_sources(app PRIVATE src/main.c)
diff --git a/samples/sensor/vcnl4040/README.rst b/samples/sensor/vcnl4040/README.rst
new file mode 100644
index 0000000..af741aa
--- /dev/null
+++ b/samples/sensor/vcnl4040/README.rst
@@ -0,0 +1,57 @@
+.. _vcnl4040_sample:
+
+VCNL4040: proximity and ambient light sensor
+############################################
+
+Overview
+********
+ This sample periodically measures proximity and light for
+ 5 sec in the interval of 300msec in polling mode. Then threshold trigger mode
+ is enabled with the high threshold value of 127 and data is fetched based
+ on interrupt. The result is displayed on the console.
+
+Requirements
+************
+
+ This sample uses the VCNL4040 sensor controlled using the I2C interface.
+ Connect sensor INT for interrupt to Feather D5 pin on the Adafruit STM32F405 Feather.
+
+References
+**********
+
+ - VCNL4040: https://www.vishay.com/docs/84274/vcnl4040.pdf
+
+Building and Running
+********************
+
+ This project outputs sensor data to the console. It requires a VCNL4040
+ sensor to be connected to the desired board.
+
+ .. zephyr-app-commands::
+    :app: samples/sensor/vcnl4040/
+    :goals: build flash
+
+
+Sample Output
+=============
+
+ .. code-block:: console
+
+    get device vcnl4040
+    Testing the polling mode.
+    Proximity: 31
+    Light (lux): 288
+
+    <repeats for 5sec every 300ms>
+
+    Polling mode test finished.
+    Testing the trigger mode.
+    Testing proximity trigger.
+    ...
+    Triggered.
+    Proximity: 122
+
+    <repeats whenever triggered for 5sec>
+
+    Threshold trigger test finished.
+    Trigger mode test finished.
diff --git a/samples/sensor/vcnl4040/boards/adafruit_feather_stm32f405.overlay b/samples/sensor/vcnl4040/boards/adafruit_feather_stm32f405.overlay
new file mode 100644
index 0000000..d500a79
--- /dev/null
+++ b/samples/sensor/vcnl4040/boards/adafruit_feather_stm32f405.overlay
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020, Richard Osterloh
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+&feather_i2c {
+	vcnl4040@60 {
+		compatible = "vishay,vcnl4040";
+		reg = <0x60>;
+		label = "VCNL4040";
+		int-gpios = <&feather_header 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+		led-current = <200>;
+		led-duty-cycle = <320>;
+		proximity-it = "8";
+		proximity-trigger = "close";
+		als-it = <640>;
+	};
+};
diff --git a/samples/sensor/vcnl4040/prj.conf b/samples/sensor/vcnl4040/prj.conf
new file mode 100644
index 0000000..37dd2aa
--- /dev/null
+++ b/samples/sensor/vcnl4040/prj.conf
@@ -0,0 +1,7 @@
+CONFIG_PRINTK=y
+CONFIG_GPIO=y
+CONFIG_I2C=y
+CONFIG_SENSOR=y
+CONFIG_VCNL4040=y
+CONFIG_VCNL4040_TRIGGER_GLOBAL_THREAD=y
+CONFIG_VCNL4040_ENABLE_ALS=y
diff --git a/samples/sensor/vcnl4040/sample.yaml b/samples/sensor/vcnl4040/sample.yaml
new file mode 100644
index 0000000..2087faf
--- /dev/null
+++ b/samples/sensor/vcnl4040/sample.yaml
@@ -0,0 +1,9 @@
+sample:
+  name: VCNL4040 Sensor Sample
+tests:
+  sample.sensor.vcnl4040:
+    harness: sensor
+    platform_allow: adafruit_feather_stm32f405
+    tags: sensors
+    depends_on: i2c gpio
+    filter: dt_compat_enabled("vishay,vcnl4040")
diff --git a/samples/sensor/vcnl4040/src/main.c b/samples/sensor/vcnl4040/src/main.c
new file mode 100644
index 0000000..e4267b6
--- /dev/null
+++ b/samples/sensor/vcnl4040/src/main.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2020 Richard Osterloh
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr.h>
+
+#include <sys/printk.h>
+#include <sys_clock.h>
+#include <stdio.h>
+
+#include <device.h>
+#include <drivers/sensor.h>
+#include <drivers/i2c.h>
+
+#define MAX_TEST_TIME	5000
+#define SLEEPTIME	300
+
+static void print_proxy_data(const struct device *dev)
+{
+	struct sensor_value pdata;
+
+	if (sensor_channel_get(dev, SENSOR_CHAN_PROX, &pdata) < 0) {
+		printf("Cannot read proximity data.\n");
+		return;
+	}
+
+	printf("Proximity: %d\n", (uint16_t) pdata.val1);
+}
+#if defined(CONFIG_VCNL4040_ENABLE_ALS)
+static void print_als_data(const struct device *dev)
+{
+	struct sensor_value val;
+
+	if (sensor_channel_get(dev, SENSOR_CHAN_LIGHT, &val) < 0) {
+		printf("ALS read error.\n");
+		return;
+	}
+
+	printf("Light (lux): %d\n", (uint16_t) val.val1);
+}
+#endif
+static void test_polling_mode(const struct device *dev)
+{
+	int32_t remaining_test_time = MAX_TEST_TIME;
+
+	do {
+		if (sensor_sample_fetch(dev) < 0) {
+			printf("sample update error.\n");
+		} else {
+			print_proxy_data(dev);
+#if defined(CONFIG_VCNL4040_ENABLE_ALS)
+			print_als_data(dev);
+#endif
+		}
+
+		/* wait a while */
+		k_sleep(K_MSEC(SLEEPTIME));
+
+		remaining_test_time -= SLEEPTIME;
+	} while (remaining_test_time > 0);
+}
+
+#if defined(CONFIG_VCNL4040_TRIGGER)
+static void trigger_handler(const struct device *dev,
+			    struct sensor_trigger *trig)
+{
+	switch (trig->type) {
+	case SENSOR_TRIG_THRESHOLD:
+		printf("Triggered.\n");
+		if (sensor_sample_fetch(dev) < 0) {
+			printf("sample update error.\n");
+		} else {
+			print_proxy_data(dev);
+		}
+		return;
+
+	default:
+		printf("trigger handler: unknown trigger type.\n");
+		return;
+	}
+}
+#endif
+
+static void test_trigger_mode(const struct device *dev)
+{
+#if defined(CONFIG_VCNL4040_TRIGGER)
+	struct sensor_trigger trig;
+	struct sensor_value attr;
+
+	printf("Testing proximity trigger.\n");
+
+	attr.val1 = 127;
+	attr.val2 = 0;
+
+	if (sensor_attr_set(dev, SENSOR_CHAN_PROX,
+			    SENSOR_ATTR_UPPER_THRESH, &attr) < 0) {
+		printf("cannot set proximity high threshold.\n");
+		return;
+	}
+
+	attr.val1 = 122;
+
+	if (sensor_attr_set(dev, SENSOR_CHAN_PROX,
+			    SENSOR_ATTR_LOWER_THRESH, &attr) < 0) {
+		printf("cannot set proximity low threshold.\n");
+		return;
+	}
+
+	trig.type = SENSOR_TRIG_THRESHOLD;
+	trig.chan = SENSOR_CHAN_PROX;
+
+	if (sensor_trigger_set(dev, &trig, trigger_handler) < 0) {
+		printf("cannot set trigger.\n");
+		return;
+	}
+
+	k_sleep(K_MSEC(MAX_TEST_TIME));
+
+	if (sensor_trigger_set(dev, &trig, NULL) < 0) {
+		printf("cannot clear trigger.\n");
+		return;
+	}
+
+	printf("Threshold trigger test finished.\n");
+#endif
+
+}
+
+void main(void)
+{
+	const struct device *vcnl;
+
+	printf("get device vcnl4040\n");
+	vcnl = device_get_binding(DT_LABEL(DT_INST(0, vishay_vcnl4040)));
+	if (!vcnl) {
+		printf("Device not found.\n");
+		return;
+	}
+
+	printf("Testing the polling mode.\n");
+	test_polling_mode(vcnl);
+	printf("Polling mode test finished.\n");
+
+	printf("Testing the trigger mode.\n");
+	test_trigger_mode(vcnl);
+	printf("Trigger mode test finished.\n");
+}