18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * GPIO based serio bus driver for bit banging the PS/2 protocol 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Danilo Krummrich <danilokrummrich@dk-develop.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/serio.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 158c2ecf20Sopenharmony_ci#include <linux/completion.h> 168c2ecf20Sopenharmony_ci#include <linux/mutex.h> 178c2ecf20Sopenharmony_ci#include <linux/preempt.h> 188c2ecf20Sopenharmony_ci#include <linux/property.h> 198c2ecf20Sopenharmony_ci#include <linux/of.h> 208c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DRIVER_NAME "ps2-gpio" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define PS2_MODE_RX 0 268c2ecf20Sopenharmony_ci#define PS2_MODE_TX 1 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define PS2_START_BIT 0 298c2ecf20Sopenharmony_ci#define PS2_DATA_BIT0 1 308c2ecf20Sopenharmony_ci#define PS2_DATA_BIT1 2 318c2ecf20Sopenharmony_ci#define PS2_DATA_BIT2 3 328c2ecf20Sopenharmony_ci#define PS2_DATA_BIT3 4 338c2ecf20Sopenharmony_ci#define PS2_DATA_BIT4 5 348c2ecf20Sopenharmony_ci#define PS2_DATA_BIT5 6 358c2ecf20Sopenharmony_ci#define PS2_DATA_BIT6 7 368c2ecf20Sopenharmony_ci#define PS2_DATA_BIT7 8 378c2ecf20Sopenharmony_ci#define PS2_PARITY_BIT 9 388c2ecf20Sopenharmony_ci#define PS2_STOP_BIT 10 398c2ecf20Sopenharmony_ci#define PS2_TX_TIMEOUT 11 408c2ecf20Sopenharmony_ci#define PS2_ACK_BIT 12 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define PS2_DEV_RET_ACK 0xfa 438c2ecf20Sopenharmony_ci#define PS2_DEV_RET_NACK 0xfe 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define PS2_CMD_RESEND 0xfe 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct ps2_gpio_data { 488c2ecf20Sopenharmony_ci struct device *dev; 498c2ecf20Sopenharmony_ci struct serio *serio; 508c2ecf20Sopenharmony_ci unsigned char mode; 518c2ecf20Sopenharmony_ci struct gpio_desc *gpio_clk; 528c2ecf20Sopenharmony_ci struct gpio_desc *gpio_data; 538c2ecf20Sopenharmony_ci bool write_enable; 548c2ecf20Sopenharmony_ci int irq; 558c2ecf20Sopenharmony_ci unsigned char rx_cnt; 568c2ecf20Sopenharmony_ci unsigned char rx_byte; 578c2ecf20Sopenharmony_ci unsigned char tx_cnt; 588c2ecf20Sopenharmony_ci unsigned char tx_byte; 598c2ecf20Sopenharmony_ci struct completion tx_done; 608c2ecf20Sopenharmony_ci struct mutex tx_mutex; 618c2ecf20Sopenharmony_ci struct delayed_work tx_work; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int ps2_gpio_open(struct serio *serio) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct ps2_gpio_data *drvdata = serio->port_data; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci enable_irq(drvdata->irq); 698c2ecf20Sopenharmony_ci return 0; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void ps2_gpio_close(struct serio *serio) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct ps2_gpio_data *drvdata = serio->port_data; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci flush_delayed_work(&drvdata->tx_work); 778c2ecf20Sopenharmony_ci disable_irq(drvdata->irq); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int __ps2_gpio_write(struct serio *serio, unsigned char val) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct ps2_gpio_data *drvdata = serio->port_data; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci disable_irq_nosync(drvdata->irq); 858c2ecf20Sopenharmony_ci gpiod_direction_output(drvdata->gpio_clk, 0); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci drvdata->mode = PS2_MODE_TX; 888c2ecf20Sopenharmony_ci drvdata->tx_byte = val; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci schedule_delayed_work(&drvdata->tx_work, usecs_to_jiffies(200)); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return 0; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int ps2_gpio_write(struct serio *serio, unsigned char val) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct ps2_gpio_data *drvdata = serio->port_data; 988c2ecf20Sopenharmony_ci int ret = 0; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (in_task()) { 1018c2ecf20Sopenharmony_ci mutex_lock(&drvdata->tx_mutex); 1028c2ecf20Sopenharmony_ci __ps2_gpio_write(serio, val); 1038c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&drvdata->tx_done, 1048c2ecf20Sopenharmony_ci msecs_to_jiffies(10000))) 1058c2ecf20Sopenharmony_ci ret = SERIO_TIMEOUT; 1068c2ecf20Sopenharmony_ci mutex_unlock(&drvdata->tx_mutex); 1078c2ecf20Sopenharmony_ci } else { 1088c2ecf20Sopenharmony_ci __ps2_gpio_write(serio, val); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return ret; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void ps2_gpio_tx_work_fn(struct work_struct *work) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct delayed_work *dwork = to_delayed_work(work); 1178c2ecf20Sopenharmony_ci struct ps2_gpio_data *drvdata = container_of(dwork, 1188c2ecf20Sopenharmony_ci struct ps2_gpio_data, 1198c2ecf20Sopenharmony_ci tx_work); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci enable_irq(drvdata->irq); 1228c2ecf20Sopenharmony_ci gpiod_direction_output(drvdata->gpio_data, 0); 1238c2ecf20Sopenharmony_ci gpiod_direction_input(drvdata->gpio_clk); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic irqreturn_t ps2_gpio_irq_rx(struct ps2_gpio_data *drvdata) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci unsigned char byte, cnt; 1298c2ecf20Sopenharmony_ci int data; 1308c2ecf20Sopenharmony_ci int rxflags = 0; 1318c2ecf20Sopenharmony_ci static unsigned long old_jiffies; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci byte = drvdata->rx_byte; 1348c2ecf20Sopenharmony_ci cnt = drvdata->rx_cnt; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (old_jiffies == 0) 1378c2ecf20Sopenharmony_ci old_jiffies = jiffies; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if ((jiffies - old_jiffies) > usecs_to_jiffies(100)) { 1408c2ecf20Sopenharmony_ci dev_err(drvdata->dev, 1418c2ecf20Sopenharmony_ci "RX: timeout, probably we missed an interrupt\n"); 1428c2ecf20Sopenharmony_ci goto err; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci old_jiffies = jiffies; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci data = gpiod_get_value(drvdata->gpio_data); 1478c2ecf20Sopenharmony_ci if (unlikely(data < 0)) { 1488c2ecf20Sopenharmony_ci dev_err(drvdata->dev, "RX: failed to get data gpio val: %d\n", 1498c2ecf20Sopenharmony_ci data); 1508c2ecf20Sopenharmony_ci goto err; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci switch (cnt) { 1548c2ecf20Sopenharmony_ci case PS2_START_BIT: 1558c2ecf20Sopenharmony_ci /* start bit should be low */ 1568c2ecf20Sopenharmony_ci if (unlikely(data)) { 1578c2ecf20Sopenharmony_ci dev_err(drvdata->dev, "RX: start bit should be low\n"); 1588c2ecf20Sopenharmony_ci goto err; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci case PS2_DATA_BIT0: 1628c2ecf20Sopenharmony_ci case PS2_DATA_BIT1: 1638c2ecf20Sopenharmony_ci case PS2_DATA_BIT2: 1648c2ecf20Sopenharmony_ci case PS2_DATA_BIT3: 1658c2ecf20Sopenharmony_ci case PS2_DATA_BIT4: 1668c2ecf20Sopenharmony_ci case PS2_DATA_BIT5: 1678c2ecf20Sopenharmony_ci case PS2_DATA_BIT6: 1688c2ecf20Sopenharmony_ci case PS2_DATA_BIT7: 1698c2ecf20Sopenharmony_ci /* processing data bits */ 1708c2ecf20Sopenharmony_ci if (data) 1718c2ecf20Sopenharmony_ci byte |= (data << (cnt - 1)); 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case PS2_PARITY_BIT: 1748c2ecf20Sopenharmony_ci /* check odd parity */ 1758c2ecf20Sopenharmony_ci if (!((hweight8(byte) & 1) ^ data)) { 1768c2ecf20Sopenharmony_ci rxflags |= SERIO_PARITY; 1778c2ecf20Sopenharmony_ci dev_warn(drvdata->dev, "RX: parity error\n"); 1788c2ecf20Sopenharmony_ci if (!drvdata->write_enable) 1798c2ecf20Sopenharmony_ci goto err; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Do not send spurious ACK's and NACK's when write fn is 1838c2ecf20Sopenharmony_ci * not provided. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci if (!drvdata->write_enable) { 1868c2ecf20Sopenharmony_ci if (byte == PS2_DEV_RET_NACK) 1878c2ecf20Sopenharmony_ci goto err; 1888c2ecf20Sopenharmony_ci else if (byte == PS2_DEV_RET_ACK) 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Let's send the data without waiting for the stop bit to be 1938c2ecf20Sopenharmony_ci * sent. It may happen that we miss the stop bit. When this 1948c2ecf20Sopenharmony_ci * happens we have no way to recover from this, certainly 1958c2ecf20Sopenharmony_ci * missing the parity bit would be recognized when processing 1968c2ecf20Sopenharmony_ci * the stop bit. When missing both, data is lost. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci serio_interrupt(drvdata->serio, byte, rxflags); 1998c2ecf20Sopenharmony_ci dev_dbg(drvdata->dev, "RX: sending byte 0x%x\n", byte); 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci case PS2_STOP_BIT: 2028c2ecf20Sopenharmony_ci /* stop bit should be high */ 2038c2ecf20Sopenharmony_ci if (unlikely(!data)) { 2048c2ecf20Sopenharmony_ci dev_err(drvdata->dev, "RX: stop bit should be high\n"); 2058c2ecf20Sopenharmony_ci goto err; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci cnt = byte = 0; 2088c2ecf20Sopenharmony_ci old_jiffies = 0; 2098c2ecf20Sopenharmony_ci goto end; /* success */ 2108c2ecf20Sopenharmony_ci default: 2118c2ecf20Sopenharmony_ci dev_err(drvdata->dev, "RX: got out of sync with the device\n"); 2128c2ecf20Sopenharmony_ci goto err; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci cnt++; 2168c2ecf20Sopenharmony_ci goto end; /* success */ 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cierr: 2198c2ecf20Sopenharmony_ci cnt = byte = 0; 2208c2ecf20Sopenharmony_ci old_jiffies = 0; 2218c2ecf20Sopenharmony_ci __ps2_gpio_write(drvdata->serio, PS2_CMD_RESEND); 2228c2ecf20Sopenharmony_ciend: 2238c2ecf20Sopenharmony_ci drvdata->rx_cnt = cnt; 2248c2ecf20Sopenharmony_ci drvdata->rx_byte = byte; 2258c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic irqreturn_t ps2_gpio_irq_tx(struct ps2_gpio_data *drvdata) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci unsigned char byte, cnt; 2318c2ecf20Sopenharmony_ci int data; 2328c2ecf20Sopenharmony_ci static unsigned long old_jiffies; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci cnt = drvdata->tx_cnt; 2358c2ecf20Sopenharmony_ci byte = drvdata->tx_byte; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (old_jiffies == 0) 2388c2ecf20Sopenharmony_ci old_jiffies = jiffies; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if ((jiffies - old_jiffies) > usecs_to_jiffies(100)) { 2418c2ecf20Sopenharmony_ci dev_err(drvdata->dev, 2428c2ecf20Sopenharmony_ci "TX: timeout, probably we missed an interrupt\n"); 2438c2ecf20Sopenharmony_ci goto err; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci old_jiffies = jiffies; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci switch (cnt) { 2488c2ecf20Sopenharmony_ci case PS2_START_BIT: 2498c2ecf20Sopenharmony_ci /* should never happen */ 2508c2ecf20Sopenharmony_ci dev_err(drvdata->dev, 2518c2ecf20Sopenharmony_ci "TX: start bit should have been sent already\n"); 2528c2ecf20Sopenharmony_ci goto err; 2538c2ecf20Sopenharmony_ci case PS2_DATA_BIT0: 2548c2ecf20Sopenharmony_ci case PS2_DATA_BIT1: 2558c2ecf20Sopenharmony_ci case PS2_DATA_BIT2: 2568c2ecf20Sopenharmony_ci case PS2_DATA_BIT3: 2578c2ecf20Sopenharmony_ci case PS2_DATA_BIT4: 2588c2ecf20Sopenharmony_ci case PS2_DATA_BIT5: 2598c2ecf20Sopenharmony_ci case PS2_DATA_BIT6: 2608c2ecf20Sopenharmony_ci case PS2_DATA_BIT7: 2618c2ecf20Sopenharmony_ci data = byte & BIT(cnt - 1); 2628c2ecf20Sopenharmony_ci gpiod_set_value(drvdata->gpio_data, data); 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci case PS2_PARITY_BIT: 2658c2ecf20Sopenharmony_ci /* do odd parity */ 2668c2ecf20Sopenharmony_ci data = !(hweight8(byte) & 1); 2678c2ecf20Sopenharmony_ci gpiod_set_value(drvdata->gpio_data, data); 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci case PS2_STOP_BIT: 2708c2ecf20Sopenharmony_ci /* release data line to generate stop bit */ 2718c2ecf20Sopenharmony_ci gpiod_direction_input(drvdata->gpio_data); 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci case PS2_TX_TIMEOUT: 2748c2ecf20Sopenharmony_ci /* Devices generate one extra clock pulse before sending the 2758c2ecf20Sopenharmony_ci * acknowledgment. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci case PS2_ACK_BIT: 2798c2ecf20Sopenharmony_ci gpiod_direction_input(drvdata->gpio_data); 2808c2ecf20Sopenharmony_ci data = gpiod_get_value(drvdata->gpio_data); 2818c2ecf20Sopenharmony_ci if (data) { 2828c2ecf20Sopenharmony_ci dev_warn(drvdata->dev, "TX: received NACK, retry\n"); 2838c2ecf20Sopenharmony_ci goto err; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci drvdata->mode = PS2_MODE_RX; 2878c2ecf20Sopenharmony_ci complete(&drvdata->tx_done); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci cnt = 1; 2908c2ecf20Sopenharmony_ci old_jiffies = 0; 2918c2ecf20Sopenharmony_ci goto end; /* success */ 2928c2ecf20Sopenharmony_ci default: 2938c2ecf20Sopenharmony_ci /* Probably we missed the stop bit. Therefore we release data 2948c2ecf20Sopenharmony_ci * line and try again. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci gpiod_direction_input(drvdata->gpio_data); 2978c2ecf20Sopenharmony_ci dev_err(drvdata->dev, "TX: got out of sync with the device\n"); 2988c2ecf20Sopenharmony_ci goto err; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci cnt++; 3028c2ecf20Sopenharmony_ci goto end; /* success */ 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cierr: 3058c2ecf20Sopenharmony_ci cnt = 1; 3068c2ecf20Sopenharmony_ci old_jiffies = 0; 3078c2ecf20Sopenharmony_ci gpiod_direction_input(drvdata->gpio_data); 3088c2ecf20Sopenharmony_ci __ps2_gpio_write(drvdata->serio, drvdata->tx_byte); 3098c2ecf20Sopenharmony_ciend: 3108c2ecf20Sopenharmony_ci drvdata->tx_cnt = cnt; 3118c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic irqreturn_t ps2_gpio_irq(int irq, void *dev_id) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct ps2_gpio_data *drvdata = dev_id; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return drvdata->mode ? ps2_gpio_irq_tx(drvdata) : 3198c2ecf20Sopenharmony_ci ps2_gpio_irq_rx(drvdata); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int ps2_gpio_get_props(struct device *dev, 3238c2ecf20Sopenharmony_ci struct ps2_gpio_data *drvdata) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci drvdata->gpio_data = devm_gpiod_get(dev, "data", GPIOD_IN); 3268c2ecf20Sopenharmony_ci if (IS_ERR(drvdata->gpio_data)) { 3278c2ecf20Sopenharmony_ci dev_err(dev, "failed to request data gpio: %ld", 3288c2ecf20Sopenharmony_ci PTR_ERR(drvdata->gpio_data)); 3298c2ecf20Sopenharmony_ci return PTR_ERR(drvdata->gpio_data); 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci drvdata->gpio_clk = devm_gpiod_get(dev, "clk", GPIOD_IN); 3338c2ecf20Sopenharmony_ci if (IS_ERR(drvdata->gpio_clk)) { 3348c2ecf20Sopenharmony_ci dev_err(dev, "failed to request clock gpio: %ld", 3358c2ecf20Sopenharmony_ci PTR_ERR(drvdata->gpio_clk)); 3368c2ecf20Sopenharmony_ci return PTR_ERR(drvdata->gpio_clk); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci drvdata->write_enable = device_property_read_bool(dev, 3408c2ecf20Sopenharmony_ci "write-enable"); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int ps2_gpio_probe(struct platform_device *pdev) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct ps2_gpio_data *drvdata; 3488c2ecf20Sopenharmony_ci struct serio *serio; 3498c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3508c2ecf20Sopenharmony_ci int error; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci drvdata = devm_kzalloc(dev, sizeof(struct ps2_gpio_data), GFP_KERNEL); 3538c2ecf20Sopenharmony_ci serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 3548c2ecf20Sopenharmony_ci if (!drvdata || !serio) { 3558c2ecf20Sopenharmony_ci error = -ENOMEM; 3568c2ecf20Sopenharmony_ci goto err_free_serio; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci error = ps2_gpio_get_props(dev, drvdata); 3608c2ecf20Sopenharmony_ci if (error) 3618c2ecf20Sopenharmony_ci goto err_free_serio; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (gpiod_cansleep(drvdata->gpio_data) || 3648c2ecf20Sopenharmony_ci gpiod_cansleep(drvdata->gpio_clk)) { 3658c2ecf20Sopenharmony_ci dev_err(dev, "GPIO data or clk are connected via slow bus\n"); 3668c2ecf20Sopenharmony_ci error = -EINVAL; 3678c2ecf20Sopenharmony_ci goto err_free_serio; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci drvdata->irq = platform_get_irq(pdev, 0); 3718c2ecf20Sopenharmony_ci if (drvdata->irq < 0) { 3728c2ecf20Sopenharmony_ci error = drvdata->irq; 3738c2ecf20Sopenharmony_ci goto err_free_serio; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci error = devm_request_irq(dev, drvdata->irq, ps2_gpio_irq, 3778c2ecf20Sopenharmony_ci IRQF_NO_THREAD, DRIVER_NAME, drvdata); 3788c2ecf20Sopenharmony_ci if (error) { 3798c2ecf20Sopenharmony_ci dev_err(dev, "failed to request irq %d: %d\n", 3808c2ecf20Sopenharmony_ci drvdata->irq, error); 3818c2ecf20Sopenharmony_ci goto err_free_serio; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Keep irq disabled until serio->open is called. */ 3858c2ecf20Sopenharmony_ci disable_irq(drvdata->irq); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci serio->id.type = SERIO_8042; 3888c2ecf20Sopenharmony_ci serio->open = ps2_gpio_open; 3898c2ecf20Sopenharmony_ci serio->close = ps2_gpio_close; 3908c2ecf20Sopenharmony_ci /* Write can be enabled in platform/dt data, but possibly it will not 3918c2ecf20Sopenharmony_ci * work because of the tough timings. 3928c2ecf20Sopenharmony_ci */ 3938c2ecf20Sopenharmony_ci serio->write = drvdata->write_enable ? ps2_gpio_write : NULL; 3948c2ecf20Sopenharmony_ci serio->port_data = drvdata; 3958c2ecf20Sopenharmony_ci serio->dev.parent = dev; 3968c2ecf20Sopenharmony_ci strlcpy(serio->name, dev_name(dev), sizeof(serio->name)); 3978c2ecf20Sopenharmony_ci strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys)); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci drvdata->serio = serio; 4008c2ecf20Sopenharmony_ci drvdata->dev = dev; 4018c2ecf20Sopenharmony_ci drvdata->mode = PS2_MODE_RX; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* Tx count always starts at 1, as the start bit is sent implicitly by 4048c2ecf20Sopenharmony_ci * host-to-device communication initialization. 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ci drvdata->tx_cnt = 1; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&drvdata->tx_work, ps2_gpio_tx_work_fn); 4098c2ecf20Sopenharmony_ci init_completion(&drvdata->tx_done); 4108c2ecf20Sopenharmony_ci mutex_init(&drvdata->tx_mutex); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci serio_register_port(serio); 4138c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, drvdata); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return 0; /* success */ 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cierr_free_serio: 4188c2ecf20Sopenharmony_ci kfree(serio); 4198c2ecf20Sopenharmony_ci return error; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic int ps2_gpio_remove(struct platform_device *pdev) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct ps2_gpio_data *drvdata = platform_get_drvdata(pdev); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci serio_unregister_port(drvdata->serio); 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 4318c2ecf20Sopenharmony_cistatic const struct of_device_id ps2_gpio_match[] = { 4328c2ecf20Sopenharmony_ci { .compatible = "ps2-gpio", }, 4338c2ecf20Sopenharmony_ci { }, 4348c2ecf20Sopenharmony_ci}; 4358c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ps2_gpio_match); 4368c2ecf20Sopenharmony_ci#endif 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic struct platform_driver ps2_gpio_driver = { 4398c2ecf20Sopenharmony_ci .probe = ps2_gpio_probe, 4408c2ecf20Sopenharmony_ci .remove = ps2_gpio_remove, 4418c2ecf20Sopenharmony_ci .driver = { 4428c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 4438c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(ps2_gpio_match), 4448c2ecf20Sopenharmony_ci }, 4458c2ecf20Sopenharmony_ci}; 4468c2ecf20Sopenharmony_cimodule_platform_driver(ps2_gpio_driver); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Danilo Krummrich <danilokrummrich@dk-develop.de>"); 4498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GPIO PS2 driver"); 4508c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 451