5 Commits

Author SHA1 Message Date
9595b72bc1 more io stuff 2025-06-16 21:30:39 +01:00
8145e1c790 start io 2025-06-15 20:53:36 +01:00
49d5847980 start io subsystem 2025-06-14 22:16:35 +01:00
34ea87ded0 use real time 2025-06-13 14:12:56 +01:00
48e9f86d33 minimize debug 2025-06-13 12:58:14 +01:00
9 changed files with 160 additions and 20 deletions

View File

@ -1,31 +1,31 @@
NAME = counter
OBJS = init.o leds.o ls7366r.o trigger.o io.o
KDIR := /lib/modules/$(shell uname -r)/build
DTC_FLAGS := -@ -I dts -O dtb
obj-m += $(NAME).o
$(NAME)-objs := init.o leds.o ls7366r.o trigger.o
$(NAME)-objs := $(OBJS)
all: $(NAME).ko $(NAME).dtbo
echo Builded Device Tree Overlay and kernel module
$(NAME).ko: init.c leds.c ls7366r.c trigger.c
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
$(NAME).ko:
make -C $(KDIR) M=$(PWD) modules
$(NAME).dtbo: $(NAME).dts
dtc -@ -I dts -O dtb -o $@ $<
dtc $(DTC_FLAGS) -o $@ $<
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
make -C $(KDIR) M=$(PWD) clean
rm -rf $(NAME).dtbo
load:
sudo dtoverlay -d . $(NAME).dtbo
@echo "Overlay loaded"
sudo insmod ./$(NAME).ko
@echo "LKM loaded"
sudo dtoverlay -d . $(NAME).dtbo && echo "Overlay loaded"
sudo insmod ./$(NAME).ko && echo "LKM loaded"
unload:
sudo rmmod ./$(NAME).ko
@echo "LKM unloaded"
sudo dtoverlay -R $(NAME)
@echo "Overlay unloaded"
sudo rmmod ./$(NAME).ko && echo "LKM unloaded"
sudo dtoverlay -R $(NAME) && echo "Overlay unloaded"
list:
sudo dtoverlay -l

26
driver/counter_io_calls.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _COUNTER_IO_CALLS_H_
#define _COUNTER_IO_CALLS_H_
#ifndef __KERNEL__
#include <stdint.h>
#define u64 uint64_t
#define u32 uint32_t
#endif
#include "leds_codes.h"
struct observation {
u64 ts_sec;
u64 ts_nsec;
u32 value;
};
struct led_cmd {
enum led_color_e color;
enum led_state_e state;
};
#define LED_CMD _IOW('l', 'c', struct led_cmd *);
#endif /* _COUNTER_IO_CALLS_H_ */

View File

@ -6,6 +6,8 @@
#include "ls7366r.h"
#include "trigger.h"
#include "leds.h"
#include "io.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Wolfgang Hottgenroth");
@ -15,6 +17,12 @@ MODULE_DESCRIPTION("Driver for the MainsCnt measurement hat");
/* module loading and unloading */
static int __init my_init(void) {
printk("counter - Loading IO subsystem...\n");
if (io_init()) {
printk("counter - Error! Could not load IO subsystem\n");
return -1;
}
printk("counter - Loading the leds driver...\n");
if(platform_driver_register(&leds_driver)) {
printk("counter - Error! Could not load leds driver\n");
@ -45,6 +53,9 @@ static void __exit my_exit(void) {
printk("counter - Unloading the interrupt driver...\n");
platform_driver_unregister(&interrupt_driver);
printk("counter - Unloading IO subsystem...\n");
io_exit();
}
module_init(my_init);

53
driver/io.c Normal file
View File

@ -0,0 +1,53 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include "io.h"
#include "counter_io_calls.h"
static dev_t io_device_no;
static struct class *io_device_class;
static struct cdev io_device;
#define DRIVER_NAME "cntiodev"
#define DRIVER_CLASS "CounterClass"
static int io_open(struct inode *device_file, struct file *instance) {
printk("counter - Info! io open was called\n");
return 0;
}
static int io_close(struct inode *device_file, struct file *instance) {
printk("counter - Info! io close was called\n");
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = io_open,
.release = io_close,
};
int io_init(void) {
printk("counter - Info! io init\n");
if (alloc_chrdev_region(&io_device_no, 0, 1, DRIVER_NAME) < 0) {
printk("counter - ERROR! Device No. could not be allocated\n");
return -1;
}
printk("counter - Info! Device No. Major: %d, Minor: %d was registered!\n", my_device_nr >> 20, my_device_nr & 0xfffff);
return 0;
}
void io_exit(void) {
}

8
driver/io.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _IO_H_
#define _IO_H_
int io_init(void);
void io_exit(void);
#endif /* _IO_H_ */

View File

@ -6,6 +6,8 @@
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include "leds.h"
/* leds stuff */
static int dt_leds_probe(struct platform_device *pdev);
@ -72,3 +74,26 @@ static void dt_leds_remove(struct platform_device *pdev) {
gpiod_put(red_led);
gpiod_put(blue_led);
}
void led_ctrl(enum led_color_e color, enum led_state_e state) {
struct gpio_desc *led;
switch (color) {
case e_RED:
led = red_led;
break;
case e_BLUE:
led = blue_led;
break;
}
int st;
switch (state) {
case e_ON:
st = 1;
break;
case e_OFF:
st = 0;
break;
}
gpiod_set_value(led, st);
}

View File

@ -3,6 +3,11 @@
#include <linux/platform_device.h>
#include "leds_codes.h"
extern struct platform_driver leds_driver;
void led_ctrl(enum led_color_e color, enum led_state_e state);
#endif /* _LEDS_H_ */

7
driver/leds_codes.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _LEDS_CODES_H_
#define _LEDS_CODES_H_
enum led_color_e { e_RED, e_BLUE };
enum led_state_e { e_ON, e_OFF };
#endif /* _LEDS_CODES_H_ */

View File

@ -9,8 +9,10 @@
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/workqueue.h>
#include <linux/timekeeping.h>
#include "ls7366r.h"
#include "leds.h"
@ -45,14 +47,14 @@ struct counter_irq_data {
struct work_struct work;
u64 timestamp;
struct spi_device *client;
u64 last_timestamp;
struct timespec64 current_timestamp;
struct timespec64 last_timestamp;
u32 last_value;
};
static struct counter_irq_data counter_irq_wq_data;
static void counter_worker(struct work_struct *work) {
struct counter_irq_data *data = container_of(work, struct counter_irq_data, work);
u64 ts = data->timestamp;
u32 counter_value;
int ret = read_otr(data->client, &counter_value);
@ -64,16 +66,20 @@ static void counter_worker(struct work_struct *work) {
if (data->last_value) {
u32 period = counter_value - data->last_value;
u64 duration = ts - data->last_timestamp;
printk("counter - Info! ts = %llu, duration = %llu, period = %u\n", ts, duration, period);
printk("counter %lld.%09lu %u\n",
(s64)((data->current_timestamp).tv_sec),
((data->current_timestamp).tv_nsec),
period);
}
data->last_value = counter_value;
data->last_timestamp = ts;
data->last_timestamp = data->current_timestamp;
}
// ISR
static irqreturn_t counter_isr(int irq, void *dev_id) {
counter_irq_wq_data.timestamp = ktime_get();
ktime_get_real_ts64(&counter_irq_wq_data.current_timestamp);
schedule_work(&counter_irq_wq_data.work);
return IRQ_HANDLED;
}
@ -86,7 +92,6 @@ static int dt_interrupt_probe(struct platform_device *pdev) {
INIT_WORK(&counter_irq_wq_data.work, counter_worker);
counter_irq_wq_data.client = ls7366r_spi_client;
counter_irq_wq_data.last_value = 0;
counter_irq_wq_data.last_timestamp = 0;
counter_interrupt = gpiod_get(dev, "intr", GPIOD_IN);
if (IS_ERR(counter_interrupt)) {