Lines Matching +full:bit +full:- +full:banging
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>
23 #define DRIVER_NAME "ps2-gpio"
66 struct ps2_gpio_data *drvdata = serio->port_data; in ps2_gpio_open()
68 enable_irq(drvdata->irq); in ps2_gpio_open()
74 struct ps2_gpio_data *drvdata = serio->port_data; in ps2_gpio_close()
76 flush_delayed_work(&drvdata->tx_work); in ps2_gpio_close()
77 disable_irq(drvdata->irq); in ps2_gpio_close()
82 struct ps2_gpio_data *drvdata = serio->port_data; in __ps2_gpio_write()
84 disable_irq_nosync(drvdata->irq); in __ps2_gpio_write()
85 gpiod_direction_output(drvdata->gpio_clk, 0); in __ps2_gpio_write()
87 drvdata->mode = PS2_MODE_TX; in __ps2_gpio_write()
88 drvdata->tx_byte = val; in __ps2_gpio_write()
90 schedule_delayed_work(&drvdata->tx_work, usecs_to_jiffies(200)); in __ps2_gpio_write()
97 struct ps2_gpio_data *drvdata = serio->port_data; in ps2_gpio_write()
101 mutex_lock(&drvdata->tx_mutex); in ps2_gpio_write()
103 if (!wait_for_completion_timeout(&drvdata->tx_done, in ps2_gpio_write()
106 mutex_unlock(&drvdata->tx_mutex); in ps2_gpio_write()
121 enable_irq(drvdata->irq); in ps2_gpio_tx_work_fn()
122 gpiod_direction_output(drvdata->gpio_data, 0); in ps2_gpio_tx_work_fn()
123 gpiod_direction_input(drvdata->gpio_clk); in ps2_gpio_tx_work_fn()
133 byte = drvdata->rx_byte; in ps2_gpio_irq_rx()
134 cnt = drvdata->rx_cnt; in ps2_gpio_irq_rx()
139 if ((jiffies - old_jiffies) > usecs_to_jiffies(100)) { in ps2_gpio_irq_rx()
140 dev_err(drvdata->dev, in ps2_gpio_irq_rx()
146 data = gpiod_get_value(drvdata->gpio_data); in ps2_gpio_irq_rx()
148 dev_err(drvdata->dev, "RX: failed to get data gpio val: %d\n", in ps2_gpio_irq_rx()
155 /* start bit should be low */ in ps2_gpio_irq_rx()
157 dev_err(drvdata->dev, "RX: start bit should be low\n"); in ps2_gpio_irq_rx()
171 byte |= (data << (cnt - 1)); in ps2_gpio_irq_rx()
177 dev_warn(drvdata->dev, "RX: parity error\n"); in ps2_gpio_irq_rx()
178 if (!drvdata->write_enable) in ps2_gpio_irq_rx()
185 if (!drvdata->write_enable) { in ps2_gpio_irq_rx()
192 /* Let's send the data without waiting for the stop bit to be in ps2_gpio_irq_rx()
193 * sent. It may happen that we miss the stop bit. When this in ps2_gpio_irq_rx()
195 * missing the parity bit would be recognized when processing in ps2_gpio_irq_rx()
196 * the stop bit. When missing both, data is lost. in ps2_gpio_irq_rx()
198 serio_interrupt(drvdata->serio, byte, rxflags); in ps2_gpio_irq_rx()
199 dev_dbg(drvdata->dev, "RX: sending byte 0x%x\n", byte); in ps2_gpio_irq_rx()
202 /* stop bit should be high */ in ps2_gpio_irq_rx()
204 dev_err(drvdata->dev, "RX: stop bit should be high\n"); in ps2_gpio_irq_rx()
211 dev_err(drvdata->dev, "RX: got out of sync with the device\n"); in ps2_gpio_irq_rx()
221 __ps2_gpio_write(drvdata->serio, PS2_CMD_RESEND); in ps2_gpio_irq_rx()
223 drvdata->rx_cnt = cnt; in ps2_gpio_irq_rx()
224 drvdata->rx_byte = byte; in ps2_gpio_irq_rx()
234 cnt = drvdata->tx_cnt; in ps2_gpio_irq_tx()
235 byte = drvdata->tx_byte; in ps2_gpio_irq_tx()
240 if ((jiffies - old_jiffies) > usecs_to_jiffies(100)) { in ps2_gpio_irq_tx()
241 dev_err(drvdata->dev, in ps2_gpio_irq_tx()
250 dev_err(drvdata->dev, in ps2_gpio_irq_tx()
251 "TX: start bit should have been sent already\n"); in ps2_gpio_irq_tx()
261 data = byte & BIT(cnt - 1); in ps2_gpio_irq_tx()
262 gpiod_set_value(drvdata->gpio_data, data); in ps2_gpio_irq_tx()
267 gpiod_set_value(drvdata->gpio_data, data); in ps2_gpio_irq_tx()
270 /* release data line to generate stop bit */ in ps2_gpio_irq_tx()
271 gpiod_direction_input(drvdata->gpio_data); in ps2_gpio_irq_tx()
279 gpiod_direction_input(drvdata->gpio_data); in ps2_gpio_irq_tx()
280 data = gpiod_get_value(drvdata->gpio_data); in ps2_gpio_irq_tx()
282 dev_warn(drvdata->dev, "TX: received NACK, retry\n"); in ps2_gpio_irq_tx()
286 drvdata->mode = PS2_MODE_RX; in ps2_gpio_irq_tx()
287 complete(&drvdata->tx_done); in ps2_gpio_irq_tx()
293 /* Probably we missed the stop bit. Therefore we release data in ps2_gpio_irq_tx()
296 gpiod_direction_input(drvdata->gpio_data); in ps2_gpio_irq_tx()
297 dev_err(drvdata->dev, "TX: got out of sync with the device\n"); in ps2_gpio_irq_tx()
307 gpiod_direction_input(drvdata->gpio_data); in ps2_gpio_irq_tx()
308 __ps2_gpio_write(drvdata->serio, drvdata->tx_byte); in ps2_gpio_irq_tx()
310 drvdata->tx_cnt = cnt; in ps2_gpio_irq_tx()
318 return drvdata->mode ? ps2_gpio_irq_tx(drvdata) : in ps2_gpio_irq()
325 drvdata->gpio_data = devm_gpiod_get(dev, "data", GPIOD_IN); in ps2_gpio_get_props()
326 if (IS_ERR(drvdata->gpio_data)) { in ps2_gpio_get_props()
328 PTR_ERR(drvdata->gpio_data)); in ps2_gpio_get_props()
329 return PTR_ERR(drvdata->gpio_data); in ps2_gpio_get_props()
332 drvdata->gpio_clk = devm_gpiod_get(dev, "clk", GPIOD_IN); in ps2_gpio_get_props()
333 if (IS_ERR(drvdata->gpio_clk)) { in ps2_gpio_get_props()
335 PTR_ERR(drvdata->gpio_clk)); in ps2_gpio_get_props()
336 return PTR_ERR(drvdata->gpio_clk); in ps2_gpio_get_props()
339 drvdata->write_enable = device_property_read_bool(dev, in ps2_gpio_get_props()
340 "write-enable"); in ps2_gpio_get_props()
349 struct device *dev = &pdev->dev; in ps2_gpio_probe()
355 error = -ENOMEM; in ps2_gpio_probe()
363 if (gpiod_cansleep(drvdata->gpio_data) || in ps2_gpio_probe()
364 gpiod_cansleep(drvdata->gpio_clk)) { in ps2_gpio_probe()
366 error = -EINVAL; in ps2_gpio_probe()
370 drvdata->irq = platform_get_irq(pdev, 0); in ps2_gpio_probe()
371 if (drvdata->irq < 0) { in ps2_gpio_probe()
372 error = drvdata->irq; in ps2_gpio_probe()
376 error = devm_request_irq(dev, drvdata->irq, ps2_gpio_irq, in ps2_gpio_probe()
380 drvdata->irq, error); in ps2_gpio_probe()
384 /* Keep irq disabled until serio->open is called. */ in ps2_gpio_probe()
385 disable_irq(drvdata->irq); in ps2_gpio_probe()
387 serio->id.type = SERIO_8042; in ps2_gpio_probe()
388 serio->open = ps2_gpio_open; in ps2_gpio_probe()
389 serio->close = ps2_gpio_close; in ps2_gpio_probe()
393 serio->write = drvdata->write_enable ? ps2_gpio_write : NULL; in ps2_gpio_probe()
394 serio->port_data = drvdata; in ps2_gpio_probe()
395 serio->dev.parent = dev; in ps2_gpio_probe()
396 strlcpy(serio->name, dev_name(dev), sizeof(serio->name)); in ps2_gpio_probe()
397 strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys)); in ps2_gpio_probe()
399 drvdata->serio = serio; in ps2_gpio_probe()
400 drvdata->dev = dev; in ps2_gpio_probe()
401 drvdata->mode = PS2_MODE_RX; in ps2_gpio_probe()
403 /* Tx count always starts at 1, as the start bit is sent implicitly by in ps2_gpio_probe()
404 * host-to-device communication initialization. in ps2_gpio_probe()
406 drvdata->tx_cnt = 1; in ps2_gpio_probe()
408 INIT_DELAYED_WORK(&drvdata->tx_work, ps2_gpio_tx_work_fn); in ps2_gpio_probe()
409 init_completion(&drvdata->tx_done); in ps2_gpio_probe()
410 mutex_init(&drvdata->tx_mutex); in ps2_gpio_probe()
426 serio_unregister_port(drvdata->serio); in ps2_gpio_remove()
432 { .compatible = "ps2-gpio", },
448 MODULE_AUTHOR("Danilo Krummrich <danilokrummrich@dk-develop.de>");