^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for the TAOS evaluation modules
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * These devices include an I2C master which can be controlled over the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * serial port.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2007 Jean Delvare <jdelvare@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/serio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define TAOS_BUFFER_SIZE 63
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define TAOS_STATE_INIT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define TAOS_STATE_IDLE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define TAOS_STATE_EOFF 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define TAOS_STATE_RECV 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define TAOS_CMD_RESET 0x12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define TAOS_CMD_ECHO_ON '+'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define TAOS_CMD_ECHO_OFF '-'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static DECLARE_WAIT_QUEUE_HEAD(wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct taos_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct i2c_adapter adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) u8 addr; /* last used address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned char buffer[TAOS_BUFFER_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) unsigned int pos; /* position inside the buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /* TAOS TSL2550 EVM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static const struct i2c_board_info tsl2550_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) I2C_BOARD_INFO("tsl2550", 0x39),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* Instantiate i2c devices based on the adapter name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) tsl2550_info.type, tsl2550_info.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return i2c_new_client_device(adapter, &tsl2550_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) unsigned short flags, char read_write, u8 command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) int size, union i2c_smbus_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct serio *serio = adapter->algo_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct taos_data *taos = serio_get_drvdata(serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) char *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /* Encode our transaction. "@" is for the device address, "$" for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) SMBus command and "#" for the data. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) p = taos->buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* The device remembers the last used address, no need to send it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) again if it's the same */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (addr != taos->addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) p += sprintf(p, "@%02X", addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) switch (size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) case I2C_SMBUS_BYTE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (read_write == I2C_SMBUS_WRITE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) sprintf(p, "$#%02X", command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) sprintf(p, "$");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) case I2C_SMBUS_BYTE_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (read_write == I2C_SMBUS_WRITE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) sprintf(p, "$%02X#%02X", command, data->byte);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) sprintf(p, "$%02X", command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* Send the transaction to the TAOS EVM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) for (p = taos->buffer; *p; p++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) serio_write(serio, *p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) taos->addr = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* Start the transaction and read the answer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) taos->pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) taos->state = TAOS_STATE_RECV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) serio_write(serio, read_write == I2C_SMBUS_WRITE ? '>' : '<');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) msecs_to_jiffies(150));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (taos->state != TAOS_STATE_IDLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) || taos->pos != 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) taos->pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* Interpret the returned string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) p = taos->buffer + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) p[3] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (!strcmp(p, "NAK"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (read_write == I2C_SMBUS_WRITE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (!strcmp(p, "ACK"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (p[0] == 'x') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * Voluntarily dropping error code of kstrtou8 since all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * error code that it could return are invalid according
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * to Documentation/i2c/fault-codes.rst.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (kstrtou8(p + 1, 16, &data->byte))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return -EPROTO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static u32 taos_smbus_func(struct i2c_adapter *adapter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static const struct i2c_algorithm taos_algorithm = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .smbus_xfer = taos_smbus_xfer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .functionality = taos_smbus_func,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) unsigned int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) struct taos_data *taos = serio_get_drvdata(serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) switch (taos->state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) case TAOS_STATE_INIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) taos->buffer[taos->pos++] = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (data == ':'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) || taos->pos == TAOS_BUFFER_SIZE - 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) taos->buffer[taos->pos] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) taos->state = TAOS_STATE_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) wake_up_interruptible(&wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) case TAOS_STATE_EOFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) taos->state = TAOS_STATE_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) wake_up_interruptible(&wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) case TAOS_STATE_RECV:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) taos->buffer[taos->pos++] = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (data == ']') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) taos->buffer[taos->pos] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) taos->state = TAOS_STATE_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) wake_up_interruptible(&wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /* Extract the adapter name from the buffer received after reset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) The buffer is modified and a pointer inside the buffer is returned. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static char *taos_adapter_name(char *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) char *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) start = strstr(buffer, "TAOS ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (!start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) end = strchr(start, '\r');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (!end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) *end = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static int taos_connect(struct serio *serio, struct serio_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct taos_data *taos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct i2c_adapter *adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) taos = kzalloc(sizeof(struct taos_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (!taos) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) taos->state = TAOS_STATE_INIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) serio_set_drvdata(serio, taos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) err = serio_open(serio, drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) goto exit_kfree;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) adapter = &taos->adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) adapter->owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) adapter->algo = &taos_algorithm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) adapter->algo_data = serio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) adapter->dev.parent = &serio->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /* Reset the TAOS evaluation module to identify it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) serio_write(serio, TAOS_CMD_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) msecs_to_jiffies(2000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (taos->state != TAOS_STATE_IDLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) dev_err(&serio->dev, "TAOS EVM reset failed (state=%d, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) "pos=%d)\n", taos->state, taos->pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) goto exit_close;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) name = taos_adapter_name(taos->buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (!name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) dev_err(&serio->dev, "TAOS EVM identification failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) goto exit_close;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) strlcpy(adapter->name, name, sizeof(adapter->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /* Turn echo off for better performance */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) taos->state = TAOS_STATE_EOFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) serio_write(serio, TAOS_CMD_ECHO_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) msecs_to_jiffies(250));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (taos->state != TAOS_STATE_IDLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) dev_err(&serio->dev, "TAOS EVM echo off failed "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) "(state=%d)\n", taos->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) goto exit_close;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) err = i2c_add_adapter(adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) goto exit_close;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) dev_info(&serio->dev, "Connected to TAOS EVM\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) taos->client = taos_instantiate_device(adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) exit_close:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) serio_close(serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) exit_kfree:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) kfree(taos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static void taos_disconnect(struct serio *serio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) struct taos_data *taos = serio_get_drvdata(serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) i2c_unregister_device(taos->client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) i2c_del_adapter(&taos->adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) serio_close(serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) kfree(taos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) dev_info(&serio->dev, "Disconnected from TAOS EVM\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static const struct serio_device_id taos_serio_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) .type = SERIO_RS232,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) .proto = SERIO_TAOSEVM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) .id = SERIO_ANY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) .extra = SERIO_ANY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) { 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) MODULE_DEVICE_TABLE(serio, taos_serio_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static struct serio_driver taos_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .name = "taos-evm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) .description = "TAOS evaluation module driver",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) .id_table = taos_serio_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .connect = taos_connect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) .disconnect = taos_disconnect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) .interrupt = taos_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) module_serio_driver(taos_drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) MODULE_DESCRIPTION("TAOS evaluation module driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) MODULE_LICENSE("GPL");