ioc: kernel-driver: Create framework for serdev driver
This commit is contained in:
		
							parent
							
								
									465dbf8c79
								
							
						
					
					
						commit
						f0f671c6fb
					
				
							
								
								
									
										2
									
								
								ioc/kernel-driver/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								ioc/kernel-driver/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -4,3 +4,5 @@ | ||||
| modules.order | ||||
| Module.symvers | ||||
| *.pro.user | ||||
| .* | ||||
| *.a | ||||
|  | ||||
| @ -1,12 +1,12 @@ | ||||
| obj-m := lw35-ioc.o | ||||
| KDIR := ~/projects/arm-linux/current | ||||
| obj-m := lw35ioc.o | ||||
| KDIR := ~/projects/linux/opi-current | ||||
| PWD := $(shell pwd) | ||||
| default: lw35-ioc.ko | ||||
| lw35-ioc.ko: lw35-ioc.c | ||||
| 	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules | ||||
| default: lw35ioc.ko | ||||
| lw35ioc.ko: lw35ioc.c | ||||
| 	$(MAKE) -C $(KDIR) M=$(PWD) | ||||
| 
 | ||||
| deploy: lw35-ioc.ko | ||||
| 	scp $< markus@opi:/home/markus/lw35-ioc/deploy | ||||
| deploy: lw35ioc.ko | ||||
| 	scp $< markus@opi:/home/markus/projects/lw35/deploy/ | ||||
| 
 | ||||
| clean: | ||||
| 	rm -f ./*.o ./*.ko ./*.mod.c modules.order Module.symvers | ||||
|  | ||||
| @ -1,28 +0,0 @@ | ||||
| /* | ||||
| 	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>; | ||||
| 	}; | ||||
| }; | ||||
							
								
								
									
										18
									
								
								ioc/kernel-driver/device-tree-opi-pc.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								ioc/kernel-driver/device-tree-opi-pc.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
 | ||||
| index 5aff8ecc66cb..c8201e79dff3 100644
 | ||||
| --- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
 | ||||
| +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
 | ||||
| @@ -211,9 +211,12 @@
 | ||||
|  }; | ||||
|   | ||||
|  &uart1 { | ||||
| +	status = "okay";
 | ||||
|  	pinctrl-names = "default"; | ||||
|  	pinctrl-0 = <&uart1_pins>; | ||||
| -	status = "disabled";
 | ||||
| +	lw35ioc@0 {
 | ||||
| +		compatible = "brother,lw35";
 | ||||
| +	};
 | ||||
|  }; | ||||
|   | ||||
|  &uart2 { | ||||
| @ -1,78 +0,0 @@ | ||||
| #include <linux/init.h> | ||||
| #include <linux/dma-mapping.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/spi/spi.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/gpio/consumer.h> | ||||
| #include <linux/interrupt.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * 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); | ||||
| 
 | ||||
							
								
								
									
										102
									
								
								ioc/kernel-driver/lw35ioc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								ioc/kernel-driver/lw35ioc.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | ||||
| #include <linux/device.h> | ||||
| #include <linux/errno.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/serdev.h> | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| MODULE_LICENSE("GPL"); | ||||
| MODULE_AUTHOR("Markus Koch"); | ||||
| MODULE_DESCRIPTION("LW-35 I/O Controller Driver"); | ||||
| MODULE_VERSION("0.1"); | ||||
| 
 | ||||
| static int debug_level = 0; | ||||
| module_param(debug_level, int, 0); | ||||
| MODULE_PARM_DESC(debug_level, "Debug level"); | ||||
| 
 | ||||
| static struct of_device_id lw35ioc_dt_ids[] = { | ||||
| { .compatible = "brother,lw35", }, | ||||
| { /* sentinel */ } | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, lw35ioc_dt_ids); | ||||
| 
 | ||||
| struct lw35ioc_priv { | ||||
| 	struct serdev_device *serdev; | ||||
| 	 | ||||
| 	// USER VARS HERE
 | ||||
| }; | ||||
| 
 | ||||
| static int lw35ioc_receive_buf(struct serdev_device *serdev, | ||||
| 				    const unsigned char *data, | ||||
| 				    size_t count) | ||||
| { | ||||
| 	dev_info(&serdev->dev, "RX: %c\n", data[0]); | ||||
| 	return 1; // TODO: return proper value
 | ||||
| } | ||||
| 
 | ||||
| static void lw35ioc_write_wakeup(struct serdev_device *serdev) | ||||
| { | ||||
| 	dev_info(&serdev->dev, "Write wakeup\n"); | ||||
| 	// schedule work here
 | ||||
| } | ||||
| 
 | ||||
| static struct serdev_device_ops lw35ioc_serdev_ops = { | ||||
| 	.receive_buf = lw35ioc_receive_buf, | ||||
| 	.write_wakeup = lw35ioc_write_wakeup, | ||||
| }; | ||||
| 
 | ||||
| static int lw35ioc_probe(struct serdev_device *serdev) | ||||
| { | ||||
| 	struct lw35ioc_priv *priv = NULL; | ||||
| 	int ret; | ||||
| 	u32 speed = 9600; | ||||
| 
 | ||||
| 	printk(KERN_INFO "lw35ioc: probe\n"); | ||||
| 
 | ||||
|         priv = devm_kzalloc(&serdev->dev, | ||||
|                     sizeof(struct lw35ioc_priv), | ||||
|                     GFP_KERNEL); | ||||
|         if (!priv) | ||||
|                 return -ENOMEM; | ||||
| 	priv->serdev = serdev; | ||||
| 	serdev_device_set_drvdata(serdev, priv); | ||||
| 	serdev_device_set_client_ops(serdev, &lw35ioc_serdev_ops); | ||||
| 
 | ||||
| 	ret = serdev_device_open(serdev); | ||||
| 	if (ret) { | ||||
| 		dev_err(&serdev->dev, "Unable to open device.\n"); | ||||
| 		goto fail0; | ||||
| 	} | ||||
| 
 | ||||
| 	speed = serdev_device_set_baudrate(serdev, speed); | ||||
| 	dev_info(&serdev->dev, "Using baudrate: %u\n", speed); | ||||
| 
 | ||||
| 	dev_info(&serdev->dev, "Loaded driver\n"); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| fail0: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void lw35ioc_remove(struct serdev_device *serdev) | ||||
| { | ||||
| 	struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev); | ||||
| 	dev_info(&serdev->dev, "remove\n"); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| static struct serdev_device_driver lw35ioc_driver = { | ||||
| 	.probe = lw35ioc_probe, | ||||
| 	.remove = lw35ioc_remove, | ||||
| 	.driver = { | ||||
| 		.name = "lw35ioc", | ||||
| 		.owner = THIS_MODULE, | ||||
| 		.of_match_table = of_match_ptr(lw35ioc_dt_ids), | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| module_serdev_device_driver(lw35ioc_driver); | ||||
| 
 | ||||
| @ -6,4 +6,4 @@ CONFIG -= qt | ||||
| INCLUDEPATH += /home/markus/projects/arm-linux/current/include | ||||
| 
 | ||||
| SOURCES += \ | ||||
|         lw35-ioc.c | ||||
|         lw35ioc.c | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user