1
0

feat(MP/kernel): create regulator

- contains the core of the module
- manual - auto mode for the temperature regulation

- use callback to communicate with temperature and led
This commit is contained in:
2026-06-05 16:17:49 +02:00
committed by Fastium
parent deff0976e0
commit df7985033a
2 changed files with 157 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
// workspace/src/06-mini-project/kernel/regulator/regulator.c
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/err.h>
#include "regulator.h"
#include "../sysfs/sysfs.h"
/* Internal state of the regulator */
static int current_mode = 1; /* 1 = Auto, 0 = Manual */
static uint32_t current_period = 2; /* Current blinking period in ms */
static struct task_struct *regulator_thread = NULL;
static struct regulator_callbacks regulator_cbs = {0};
/* --- Sysfs Callbacks --- */
static uint32_t cb_get_temperature(void) {
return regulator_cbs.get_temperature();
}
static int cb_get_mode(void) {
return current_mode;
}
static void cb_set_mode(int mode) {
/* Accept only 0 or 1 as valid modes */
if (mode == 0 || mode == 1) {
current_mode = mode;
pr_info("regulator: Mode switched to %s\n", mode ? "Auto" : "Manual");
}
}
static uint32_t cb_get_period(void) {
return current_period;
}
static void cb_set_period(uint32_t freq) {
/* Allow period changes only in Manual mode */
if (current_mode == 0) {
current_period = freq;
regulator_cbs.adjust_period(current_period);
pr_info("regulator: Manual period set to %u ms\n", current_period);
} else {
pr_warn("regulator: Cannot set period manually in auto mode\n");
}
}
/* Pack callbacks into the structure expected by sysfs */
static struct sysfs_callbacks sysfs_cbs = {
.get_temperature = cb_get_temperature,
.get_mode = cb_get_mode,
.set_mode = cb_set_mode,
.get_period = cb_get_period,
.set_period = cb_set_period,
};
/* --- Auto Mode Logic --- */
static void process_auto_mode(void) {
uint32_t temp_milli = regulator_cbs.get_temperature();
uint32_t temp_c = temp_milli / 1000;
uint32_t new_period = 2;
/* Determine period based on temperature thresholds */
if (temp_c < 35) {
new_period = 500;
} else if (temp_c < 40) {
new_period = 200;
} else if (temp_c < 45) {
new_period = 100;
} else {
new_period = 50;
}
/* Apply only if the period has changed to avoid unnecessary hardware updates */
if (new_period != current_period) {
current_period = new_period;
regulator_cbs.adjust_period(current_period);
pr_info("regulator: Auto mode adjusted period to %u ms (Temp: %u C)\n",
current_period, temp_c);
}
}
/* Background thread checking the temperature periodically */
static int regulator_thread_fn(void *data) {
while (!kthread_should_stop()) {
if (current_mode == 1) {
process_auto_mode();
}
msleep(1000);
}
return 0;
}
/* --- Public API --- */
int regulator_init(struct regulator_callbacks *cbs) {
if (cbs == NULL) {
pr_err("regulator: Callbacks are NULL\n");
return -EINVAL;
}
// register callbacks
regulator_cbs = *cbs;
/* Initialize sysfs and inject our brain callbacks */
int ret = temp_regulator_sysfs_init(&sysfs_cbs);
if (ret != 0) {
return ret;
}
/* Start the background decision loop */
regulator_thread = kthread_run(regulator_thread_fn, NULL, "regulator_logic");
if (IS_ERR(regulator_thread)) {
temp_regulator_sysfs_exit();
return PTR_ERR(regulator_thread);
}
/* Set initial hardware state */
regulator_cbs.adjust_period(current_period);
return 0;
}
void regulator_exit(void) {
if (regulator_thread != NULL) {
kthread_stop(regulator_thread);
regulator_thread = NULL;
}
temp_regulator_sysfs_exit();
}

View File

@@ -0,0 +1,20 @@
// workspace/src/06-mini-project/kernel/regulator/regulator.h
#ifndef REGULATOR_H
#define REGULATOR_H
#include <linux/types.h>
/* Callbacks for adjusting period and getting temperature */
struct regulator_callbacks {
void (*adjust_period)(int new_period_ms);
uint32_t (*get_temperature)(void);
};
/* Initialize the regulator logic, background thread, and sysfs. Register the callbacks with other parts */
int regulator_init(struct regulator_callbacks *cbs);
/* Stop the regulator logic and clean up */
void regulator_exit(void);
#endif /* REGULATOR_H */