From 52fc4af393e68e511f9ee715efadb055ca9e2bef Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Tue, 20 Aug 2019 13:55:09 +0200
Subject: [PATCH] feat(epicardium): Add hardware/peripheral-lock module

Signed-off-by: Rahix <rahix@rahix.de>
---
 epicardium/modules/hardware.c  |  5 +++
 epicardium/modules/hw-lock.c   | 62 ++++++++++++++++++++++++++++++++++
 epicardium/modules/meson.build |  1 +
 epicardium/modules/modules.h   | 11 ++++++
 epicardium/modules/pmic.c      |  6 ++++
 5 files changed, 85 insertions(+)
 create mode 100644 epicardium/modules/hw-lock.c

diff --git a/epicardium/modules/hardware.c b/epicardium/modules/hardware.c
index 3905ceb81..75a995e97 100644
--- a/epicardium/modules/hardware.c
+++ b/epicardium/modules/hardware.c
@@ -150,6 +150,11 @@ int hardware_early_init(void)
 	 */
 	stream_init();
 
+	/*
+	 * Hardware/Peripheral Locks
+	 */
+	hwlock_init();
+
 	return 0;
 }
 
diff --git a/epicardium/modules/hw-lock.c b/epicardium/modules/hw-lock.c
new file mode 100644
index 000000000..f02a5882b
--- /dev/null
+++ b/epicardium/modules/hw-lock.c
@@ -0,0 +1,62 @@
+#include "modules/log.h"
+#include "modules/modules.h"
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+#include <errno.h>
+
+static StaticSemaphore_t hwlock_mutex_data[_HWLOCK_MAX];
+static SemaphoreHandle_t hwlock_mutex[_HWLOCK_MAX];
+/* Which task is holding the lock */
+static TaskHandle_t hwlock_tasks[_HWLOCK_MAX];
+
+void hwlock_init(void)
+{
+	for (int i = 0; i < _HWLOCK_MAX; i++) {
+		hwlock_mutex[i] =
+			xSemaphoreCreateMutexStatic(&hwlock_mutex_data[i]);
+	}
+}
+
+int hwlock_acquire(enum hwlock_periph p, TickType_t wait)
+{
+	if (p >= _HWLOCK_MAX) {
+		return -EINVAL;
+	}
+
+	if (xSemaphoreTake(hwlock_mutex[p], wait) != pdTRUE) {
+		LOG_WARN("hwlock", "Lock %u is busy.", p);
+		return -EBUSY;
+	}
+
+	hwlock_tasks[p] = xTaskGetCurrentTaskHandle();
+
+	return 0;
+}
+
+int hwlock_release(enum hwlock_periph p)
+{
+	int ret = 0;
+
+	if (p >= _HWLOCK_MAX) {
+		return -EINVAL;
+	}
+
+	if (hwlock_tasks[p] != xTaskGetCurrentTaskHandle()) {
+		LOG_ERR("hwlock",
+			"Lock %u is released by task \"%s\" while it was acquired by \"%s\"",
+			p,
+			pcTaskGetName(NULL),
+			pcTaskGetName(hwlock_tasks[p]));
+		ret = -EACCES;
+	}
+
+	if (xSemaphoreGive(hwlock_mutex[p]) != pdTRUE) {
+		LOG_ERR("hwlock", "Lock %u not released correctly.", p);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build
index 31e7f5c07..4966be6c9 100644
--- a/epicardium/modules/meson.build
+++ b/epicardium/modules/meson.build
@@ -5,6 +5,7 @@ module_sources = files(
   'fileops.c',
   'gpio.c',
   'hardware.c',
+  'hw-lock.c',
   'leds.c',
   'lifecycle.c',
   'light_sensor.c',
diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h
index 535dcf5c1..abf1c7709 100644
--- a/epicardium/modules/modules.h
+++ b/epicardium/modules/modules.h
@@ -37,6 +37,17 @@ void vBleTask(void *pvParameters);
 bool ble_shall_start(void);
 void ble_uart_write(uint8_t *pValue, uint8_t len);
 
+/* ---------- Hardware (Peripheral) Locks ---------------------------------- */
+void hwlock_init(void);
+
+enum hwlock_periph {
+	HWLOCK_I2C = 0,
+	_HWLOCK_MAX,
+};
+
+int hwlock_acquire(enum hwlock_periph p, TickType_t wait);
+int hwlock_release(enum hwlock_periph p);
+
 /* ---------- Display ------------------------------------------------------ */
 /* Forces an unlock of the display. Only to be used in Epicardium */
 void disp_forcelock();
diff --git a/epicardium/modules/pmic.c b/epicardium/modules/pmic.c
index 492545bb3..c02691dc2 100644
--- a/epicardium/modules/pmic.c
+++ b/epicardium/modules/pmic.c
@@ -45,7 +45,13 @@ void vPmicTask(void *pvParameters)
 			MAX77650_setSFT_RST(0x2);
 		}
 
+		while (hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(500)) < 0) {
+			LOG_WARN("pmic", "Failed to acquire I2C. Retrying ...");
+			vTaskDelay(pdMS_TO_TICKS(500));
+		}
+
 		uint8_t int_flag = MAX77650_getINT_GLBL();
+		hwlock_release(HWLOCK_I2C);
 
 		if (int_flag & MAX77650_INT_nEN_F) {
 			/* Button was pressed */
-- 
GitLab