diff --git a/ioc/kernel-driver/device-tree-opi-pc.patch b/ioc/kernel-driver/device-tree-opi-pc.patch index 43c7d73..2b62007 100644 --- a/ioc/kernel-driver/device-tree-opi-pc.patch +++ b/ioc/kernel-driver/device-tree-opi-pc.patch @@ -1,18 +1,41 @@ 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 +index c8201e79dff3..5407742acad6 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 @@ +@@ -210,12 +210,22 @@ &uart0 { + status = "okay"; }; ++&pio { ++ lw35ioc_pins: lw35ioc-pins { ++ pins = "PA10"; ++ function = "gpio_out"; ++ }; ++}; ++ &uart1 { -+ status = "okay"; + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart1_pins>; -- status = "disabled"; -+ lw35ioc@0 { -+ compatible = "brother,lw35"; -+ }; + lw35ioc@0 { + compatible = "brother,lw35"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&lw35ioc_pins>; ++ rst-gpios = <&pio 0 10 GPIO_ACTIVE_LOW>; + }; }; - &uart2 { +@@ -242,3 +252,13 @@ &usbphy { + /* VBUS on USB host ports are always on */ + status = "okay"; + }; ++ ++&spi0 { ++ status = "okay"; ++ lmg6202ulyt@0 { ++ compatible = "hitachi,lmg6202ulyt"; ++ reg = <0x0>; ++ spi-max-frequency = <2000000>; ++ cs-gpios = <0>, <&pio 0 3 GPIO_ACTIVE_LOW>; ++ }; ++}; diff --git a/ioc/kernel-driver/lw35ioc.c b/ioc/kernel-driver/lw35ioc.c index e7ffee2..ff2e637 100644 --- a/ioc/kernel-driver/lw35ioc.c +++ b/ioc/kernel-driver/lw35ioc.c @@ -7,6 +7,7 @@ #include #include #include +#include // #define ENABLE_DEBUG ENABLE_DEBUG @@ -43,20 +44,25 @@ static int keycode_map[] = { KEY_SYSRQ }; -enum lw35ioc_state {SYNC, TYPE, KEYBOARD, PRINTER}; +enum lw35ioc_state {PASSIVE, PASSTHROUGH, ACTIVE}; + +enum lw35ioc_packet_state {SYNC, TYPE, KEYBOARD, PRINTER}; struct lw35ioc_packet { - enum lw35ioc_state state; + enum lw35ioc_packet_state state; }; struct lw35ioc_priv { struct serdev_device *serdev; struct input_dev *input_dev; + struct gpio_desc *gpio_rst; /* GPIO to reset both AVRs */ + enum lw35ioc_state state; struct lw35ioc_packet packet; }; -static int lw35ioc_receive_buf(struct serdev_device *serdev, + +static int lw35ioc_process_buf(struct serdev_device *serdev, const unsigned char *data, size_t count) { @@ -107,6 +113,17 @@ static int lw35ioc_receive_buf(struct serdev_device *serdev, return i; } +static int lw35ioc_receive_buf(struct serdev_device *serdev, + const unsigned char *data, + size_t count) +{ + struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev); + if (priv->state == ACTIVE) + return lw35ioc_process_buf(serdev, data, count); + + return count; /* Pretend we read all data */ +} + static void lw35ioc_write_wakeup(struct serdev_device *serdev) { dev_info(&serdev->dev, "Write wakeup\n"); @@ -118,6 +135,14 @@ static struct serdev_device_ops lw35ioc_serdev_ops = { .write_wakeup = lw35ioc_write_wakeup, }; +static void lw35ioc_set_hw_reset(struct serdev_device *serdev, + int reset_active) +{ + struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev); + + gpiod_set_value(priv->gpio_rst, !reset_active); +} + static int lw35ioc_probe(struct serdev_device *serdev) { struct lw35ioc_priv *priv = NULL; @@ -128,6 +153,7 @@ static int lw35ioc_probe(struct serdev_device *serdev) printk(KERN_INFO "lw35ioc: probe\n"); + /* Allocate memory */ priv = devm_kzalloc(&serdev->dev, sizeof(struct lw35ioc_priv), GFP_KERNEL); @@ -135,11 +161,13 @@ static int lw35ioc_probe(struct serdev_device *serdev) printk(KERN_ERR "lw35ioc: Not enough memory.\n"); return -ENOMEM; } + priv->state = PASSIVE; priv->serdev = serdev; priv->packet.state = SYNC; serdev_device_set_drvdata(serdev, priv); serdev_device_set_client_ops(serdev, &lw35ioc_serdev_ops); + /* Register input device */ input_dev = devm_input_allocate_device(&serdev->dev); if (!input_dev) { dev_err(&serdev->dev, "Unable to allocate input device.\n"); @@ -156,25 +184,37 @@ static int lw35ioc_probe(struct serdev_device *serdev) ret = input_register_device(input_dev); if (ret) { dev_err(&serdev->dev, "Unable to register input device.\n"); - goto fail0; + goto fail_input; } ret = serdev_device_open(serdev); if (ret) { dev_err(&serdev->dev, "Unable to open device.\n"); - goto fail1; + goto fail_serdev; } speed = serdev_device_set_baudrate(serdev, speed); dev_info(&serdev->dev, "Using baudrate: %u\n", speed); + /* Register GPIO */ + priv->gpio_rst = gpiod_get_index(&serdev->dev, + "rst", + 0, + GPIOD_OUT_LOW); + lw35ioc_set_hw_reset(serdev, 0); + + if (IS_ERR(priv->gpio_rst)) { + dev_err(&serdev->dev, "Unable to get reset GPIO.\n"); + ret = -ENODEV; + goto fail_gpio; + } dev_info(&serdev->dev, "Loaded driver.\n"); return 0; - -fail1: +fail_gpio: +fail_serdev: input_unregister_device(input_dev); -fail0: +fail_input: devm_kfree(&serdev->dev, input_dev); return ret; } @@ -183,6 +223,8 @@ static void lw35ioc_remove(struct serdev_device *serdev) { struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev); + lw35ioc_set_hw_reset(serdev, 1); + gpiod_put(priv->gpio_rst); serdev_device_close(priv->serdev); input_unregister_device(priv->input_dev);