Lines Matching +full:tx +full:- +full:clk +full:- +full:delay +full:- +full:ps
1 // SPDX-License-Identifier: GPL-2.0-only
3 * GPIO based serio bus driver for bit banging the PS/2 protocol
5 * Author: Danilo Krummrich <danilokrummrich@dk-develop.de>
21 #include <linux/delay.h>
24 #define DRIVER_NAME "ps2-gpio"
50 * interrupt interval should be ~60us. Let's allow +/- 20us for frequency
61 * |-----------------| |--------|
68 #define PS2_IRQ_MIN_INTERVAL_US (PS2_CLK_MIN_INTERVAL_US - 20)
93 } tx; member
98 struct ps2_gpio_data *drvdata = serio->port_data; in ps2_gpio_open()
100 drvdata->t_irq_last = 0; in ps2_gpio_open()
101 drvdata->tx.t_xfer_end = 0; in ps2_gpio_open()
103 enable_irq(drvdata->irq); in ps2_gpio_open()
109 struct ps2_gpio_data *drvdata = serio->port_data; in ps2_gpio_close()
111 flush_delayed_work(&drvdata->tx.work); in ps2_gpio_close()
112 disable_irq(drvdata->irq); in ps2_gpio_close()
117 struct ps2_gpio_data *drvdata = serio->port_data; in __ps2_gpio_write()
119 disable_irq_nosync(drvdata->irq); in __ps2_gpio_write()
120 gpiod_direction_output(drvdata->gpio_clk, 0); in __ps2_gpio_write()
122 drvdata->mode = PS2_MODE_TX; in __ps2_gpio_write()
123 drvdata->tx.byte = val; in __ps2_gpio_write()
125 schedule_delayed_work(&drvdata->tx.work, usecs_to_jiffies(200)); in __ps2_gpio_write()
132 struct ps2_gpio_data *drvdata = serio->port_data; in ps2_gpio_write()
136 mutex_lock(&drvdata->tx.mutex); in ps2_gpio_write()
138 if (!wait_for_completion_timeout(&drvdata->tx.complete, in ps2_gpio_write()
141 mutex_unlock(&drvdata->tx.mutex); in ps2_gpio_write()
154 tx.work); in ps2_gpio_tx_work_fn()
156 drvdata->tx.t_xfer_start = ktime_get(); in ps2_gpio_tx_work_fn()
157 enable_irq(drvdata->irq); in ps2_gpio_tx_work_fn()
158 gpiod_direction_output(drvdata->gpio_data, 0); in ps2_gpio_tx_work_fn()
159 gpiod_direction_input(drvdata->gpio_clk); in ps2_gpio_tx_work_fn()
169 byte = drvdata->rx.byte; in ps2_gpio_irq_rx()
170 cnt = drvdata->rx.cnt; in ps2_gpio_irq_rx()
172 drvdata->t_irq_now = ktime_get(); in ps2_gpio_irq_rx()
176 * a TX xfer finished. in ps2_gpio_irq_rx()
178 us_delta = ktime_us_delta(drvdata->t_irq_now, drvdata->tx.t_xfer_end); in ps2_gpio_irq_rx()
182 us_delta = ktime_us_delta(drvdata->t_irq_now, drvdata->t_irq_last); in ps2_gpio_irq_rx()
184 dev_err(drvdata->dev, in ps2_gpio_irq_rx()
191 drvdata->t_irq_last = drvdata->t_irq_now; in ps2_gpio_irq_rx()
193 data = gpiod_get_value(drvdata->gpio_data); in ps2_gpio_irq_rx()
195 dev_err(drvdata->dev, "RX: failed to get data gpio val: %d\n", in ps2_gpio_irq_rx()
204 dev_err(drvdata->dev, "RX: start bit should be low\n"); in ps2_gpio_irq_rx()
218 byte |= (data << (cnt - 1)); in ps2_gpio_irq_rx()
224 dev_warn(drvdata->dev, "RX: parity error\n"); in ps2_gpio_irq_rx()
225 if (!drvdata->write_enable) in ps2_gpio_irq_rx()
232 dev_err(drvdata->dev, "RX: stop bit should be high\n"); in ps2_gpio_irq_rx()
240 if (!drvdata->write_enable) { in ps2_gpio_irq_rx()
247 serio_interrupt(drvdata->serio, byte, rxflags); in ps2_gpio_irq_rx()
248 dev_dbg(drvdata->dev, "RX: sending byte 0x%x\n", byte); in ps2_gpio_irq_rx()
254 dev_err(drvdata->dev, "RX: got out of sync with the device\n"); in ps2_gpio_irq_rx()
263 __ps2_gpio_write(drvdata->serio, PS2_CMD_RESEND); in ps2_gpio_irq_rx()
265 drvdata->rx.cnt = cnt; in ps2_gpio_irq_rx()
266 drvdata->rx.byte = byte; in ps2_gpio_irq_rx()
276 cnt = drvdata->tx.cnt; in ps2_gpio_irq_tx()
277 byte = drvdata->tx.byte; in ps2_gpio_irq_tx()
279 drvdata->t_irq_now = ktime_get(); in ps2_gpio_irq_tx()
287 us_delta = ktime_us_delta(drvdata->t_irq_now, in ps2_gpio_irq_tx()
288 drvdata->tx.t_xfer_start); in ps2_gpio_irq_tx()
292 us_delta = ktime_us_delta(drvdata->t_irq_now, drvdata->t_irq_last); in ps2_gpio_irq_tx()
294 dev_err(drvdata->dev, in ps2_gpio_irq_tx()
295 "TX: timeout, probably we missed an interrupt\n"); in ps2_gpio_irq_tx()
301 drvdata->t_irq_last = drvdata->t_irq_now; in ps2_gpio_irq_tx()
306 dev_err(drvdata->dev, in ps2_gpio_irq_tx()
307 "TX: start bit should have been sent already\n"); in ps2_gpio_irq_tx()
317 data = byte & BIT(cnt - 1); in ps2_gpio_irq_tx()
318 gpiod_set_value(drvdata->gpio_data, data); in ps2_gpio_irq_tx()
323 gpiod_set_value(drvdata->gpio_data, data); in ps2_gpio_irq_tx()
327 gpiod_direction_input(drvdata->gpio_data); in ps2_gpio_irq_tx()
330 data = gpiod_get_value(drvdata->gpio_data); in ps2_gpio_irq_tx()
332 dev_warn(drvdata->dev, "TX: received NACK, retry\n"); in ps2_gpio_irq_tx()
336 drvdata->tx.t_xfer_end = ktime_get(); in ps2_gpio_irq_tx()
337 drvdata->mode = PS2_MODE_RX; in ps2_gpio_irq_tx()
338 complete(&drvdata->tx.complete); in ps2_gpio_irq_tx()
347 gpiod_direction_input(drvdata->gpio_data); in ps2_gpio_irq_tx()
348 dev_err(drvdata->dev, "TX: got out of sync with the device\n"); in ps2_gpio_irq_tx()
357 gpiod_direction_input(drvdata->gpio_data); in ps2_gpio_irq_tx()
358 __ps2_gpio_write(drvdata->serio, drvdata->tx.byte); in ps2_gpio_irq_tx()
360 drvdata->tx.cnt = cnt; in ps2_gpio_irq_tx()
368 return drvdata->mode ? ps2_gpio_irq_tx(drvdata) : in ps2_gpio_irq()
377 /* Enforce open drain, since this is required by the PS/2 bus. */ in ps2_gpio_get_props()
380 drvdata->gpio_data = devm_gpiod_get(dev, "data", gflags); in ps2_gpio_get_props()
381 if (IS_ERR(drvdata->gpio_data)) { in ps2_gpio_get_props()
383 PTR_ERR(drvdata->gpio_data)); in ps2_gpio_get_props()
384 return PTR_ERR(drvdata->gpio_data); in ps2_gpio_get_props()
387 drvdata->gpio_clk = devm_gpiod_get(dev, "clk", gflags); in ps2_gpio_get_props()
388 if (IS_ERR(drvdata->gpio_clk)) { in ps2_gpio_get_props()
390 PTR_ERR(drvdata->gpio_clk)); in ps2_gpio_get_props()
391 return PTR_ERR(drvdata->gpio_clk); in ps2_gpio_get_props()
394 drvdata->write_enable = device_property_read_bool(dev, in ps2_gpio_get_props()
395 "write-enable"); in ps2_gpio_get_props()
404 struct device *dev = &pdev->dev; in ps2_gpio_probe()
410 error = -ENOMEM; in ps2_gpio_probe()
418 if (gpiod_cansleep(drvdata->gpio_data) || in ps2_gpio_probe()
419 gpiod_cansleep(drvdata->gpio_clk)) { in ps2_gpio_probe()
420 dev_err(dev, "GPIO data or clk are connected via slow bus\n"); in ps2_gpio_probe()
421 error = -EINVAL; in ps2_gpio_probe()
425 drvdata->irq = platform_get_irq(pdev, 0); in ps2_gpio_probe()
426 if (drvdata->irq < 0) { in ps2_gpio_probe()
427 error = drvdata->irq; in ps2_gpio_probe()
431 error = devm_request_irq(dev, drvdata->irq, ps2_gpio_irq, in ps2_gpio_probe()
436 drvdata->irq, error); in ps2_gpio_probe()
440 serio->id.type = SERIO_8042; in ps2_gpio_probe()
441 serio->open = ps2_gpio_open; in ps2_gpio_probe()
442 serio->close = ps2_gpio_close; in ps2_gpio_probe()
447 serio->write = drvdata->write_enable ? ps2_gpio_write : NULL; in ps2_gpio_probe()
448 serio->port_data = drvdata; in ps2_gpio_probe()
449 serio->dev.parent = dev; in ps2_gpio_probe()
450 strscpy(serio->name, dev_name(dev), sizeof(serio->name)); in ps2_gpio_probe()
451 strscpy(serio->phys, dev_name(dev), sizeof(serio->phys)); in ps2_gpio_probe()
453 drvdata->serio = serio; in ps2_gpio_probe()
454 drvdata->dev = dev; in ps2_gpio_probe()
455 drvdata->mode = PS2_MODE_RX; in ps2_gpio_probe()
458 * Tx count always starts at 1, as the start bit is sent implicitly by in ps2_gpio_probe()
459 * host-to-device communication initialization. in ps2_gpio_probe()
461 drvdata->tx.cnt = 1; in ps2_gpio_probe()
463 INIT_DELAYED_WORK(&drvdata->tx.work, ps2_gpio_tx_work_fn); in ps2_gpio_probe()
464 init_completion(&drvdata->tx.complete); in ps2_gpio_probe()
465 mutex_init(&drvdata->tx.mutex); in ps2_gpio_probe()
481 serio_unregister_port(drvdata->serio); in ps2_gpio_remove()
486 { .compatible = "ps2-gpio", },
502 MODULE_AUTHOR("Danilo Krummrich <danilokrummrich@dk-develop.de>");