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:
137
src/06-mini-project/kernel/regulator/regulator.c
Normal file
137
src/06-mini-project/kernel/regulator/regulator.c
Normal 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();
|
||||
}
|
||||
20
src/06-mini-project/kernel/regulator/regulator.h
Normal file
20
src/06-mini-project/kernel/regulator/regulator.h
Normal 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 */
|
||||
Reference in New Issue
Block a user