diff --git a/ioc/kernel-driver/.gitignore b/ioc/kernel-driver/.gitignore new file mode 100644 index 0000000..f7f5fc8 --- /dev/null +++ b/ioc/kernel-driver/.gitignore @@ -0,0 +1,6 @@ +*.o +*.ko +*.mod.c +modules.order +Module.symvers +*.pro.user diff --git a/ioc/kernel-driver/Makefile b/ioc/kernel-driver/Makefile new file mode 100644 index 0000000..a68eff4 --- /dev/null +++ b/ioc/kernel-driver/Makefile @@ -0,0 +1,14 @@ +obj-m := lw35-ioc.o +KDIR := ~/projects/arm-linux/current +PWD := $(shell pwd) +default: lw35-ioc.ko +lw35-ioc.ko: lw35-ioc.c + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules + +deploy: lw35-ioc.ko + scp $< markus@opi:/home/markus/lw35-ioc/deploy + +clean: + rm -f ./*.o ./*.ko ./*.mod.c modules.order Module.symvers + +.phony: deploy clean diff --git a/ioc/kernel-driver/device-tree-opi-pc.dtb b/ioc/kernel-driver/device-tree-opi-pc.dtb new file mode 100644 index 0000000..24d23dd --- /dev/null +++ b/ioc/kernel-driver/device-tree-opi-pc.dtb @@ -0,0 +1,28 @@ +/* + Reading: https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +*/ + +&spi1 { + status = "okay"; + lw35ioc@0 { + compatible = "brother,lw35ioc"; + reg = <0x0>; + spi-max-frequency = <2000000>; + + pinctrl-names = "default"; + pinctrl-0 = <&lw35ioc>; + data-gpios = <&pio 0 7 GPIO_ACTIVE_HIGH>; /* TODO: get real IO num */ + + interrupt-parent = <&pio>; + interrupts = <52 2>; + }; +}; + +&pio { + lmg6202ulyt_opc: lmg6202ulyt_pins { + pins = "PA7"; + function = "gpio_out"; + interrupt-controller; + #interrupt-cells = <1>; + }; +}; diff --git a/ioc/kernel-driver/lw35-ioc.c b/ioc/kernel-driver/lw35-ioc.c new file mode 100644 index 0000000..68338c7 --- /dev/null +++ b/ioc/kernel-driver/lw35-ioc.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * irq in general: https://notes.shichao.io/lkd/ch7/ + * raspi irqs: http://morethanuser.blogspot.com/2013/04/raspberry-pi-gpio-interrupts-in-kernel.html + * kdoc devtree irq: https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + * GPIOD doc (including irq): https://www.kernel.org/doc/Documentation/gpio/consumer.txt + */ + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Markus Koch"); +MODULE_DESCRIPTION("LW35 I/O Controller Driver"); +MODULE_VERSION("0.1"); + +static char *testparam = "param"; +module_param(testparam, charp, S_IRUGO); +MODULE_PARM_DESC(testparam, "A test parameter"); + +static struct of_device_id lw35ioc_dt_ids[] = { +{ .compatible = "brother,lw35", }, +{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, lw35ioc_dt_ids); + +struct lw35ioc_priv { + struct spi_device *spi; + + // USER VARS HERE +}; + +static int lw35ioc_probe(struct spi_device *spi) +{ + struct lw35ioc_priv *priv = NULL; + + printk(KERN_INFO "lw35ioc: probe\n"); + + priv = devm_kzalloc(&spi->dev, + sizeof(struct lw35ioc_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + spi_set_drvdata(spi, priv); + + priv->spi = spi; + + printk(KERN_INFO "lw35ioc: Loaded driver\n"); + + return 0; + + // Error handlers go here +} + +static int lw35ioc_remove(struct spi_device *spi) +{ + struct lw35ioc_priv *priv = spi_get_drvdata(spi); + + return 0; +} + +static struct spi_driver lw35ioc_driver = { + .probe = lw35ioc_probe, + .remove = lw35ioc_remove, + .driver = { + .name = "lw35ioc", + .owner = THIS_MODULE, + .of_match_table = lw35ioc_dt_ids, + }, +}; +module_spi_driver(lw35ioc_driver); + diff --git a/ioc/kernel-driver/lw35-ioc.pro b/ioc/kernel-driver/lw35-ioc.pro new file mode 100644 index 0000000..e80adec --- /dev/null +++ b/ioc/kernel-driver/lw35-ioc.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +INCLUDEPATH += /home/markus/projects/arm-linux/current/include + +SOURCES += \ + lw35-ioc.c