From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- kernel/drivers/input/touchscreen/raydium_i2c_ts.c | 210 +++++++++++++++++++++++++++++---------------------- 1 files changed, 119 insertions(+), 91 deletions(-) diff --git a/kernel/drivers/input/touchscreen/raydium_i2c_ts.c b/kernel/drivers/input/touchscreen/raydium_i2c_ts.c index 1a8c740..bdb3e2c 100644 --- a/kernel/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/kernel/drivers/input/touchscreen/raydium_i2c_ts.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Raydium touchscreen I2C driver. * * Copyright (C) 2012-2014, Raydium Semiconductor Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, and only version 2, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. * * Raydium reserves the right to make changes without further notice * to the materials described herein. Raydium does not assume any @@ -60,6 +51,7 @@ /* Touch relative info */ #define RM_MAX_RETRIES 3 +#define RM_RETRY_DELAY_MS 20 #define RM_MAX_TOUCH_NUM 10 #define RM_BOOT_DELAY_MS 100 @@ -145,83 +137,134 @@ bool wake_irq_enabled; }; -static int raydium_i2c_send(struct i2c_client *client, - u8 addr, const void *data, size_t len) -{ - u8 *buf; - int tries = 0; - int ret; +/* + * Header to be sent for RM_CMD_BANK_SWITCH command. This is used by + * raydium_i2c_{read|send} below. + */ +struct __packed raydium_bank_switch_header { + u8 cmd; + __be32 be_addr; +}; - buf = kmalloc(len + 1, GFP_KERNEL); - if (!buf) +static int raydium_i2c_xfer(struct i2c_client *client, u32 addr, + struct i2c_msg *xfer, size_t xfer_count) +{ + int ret; + /* + * If address is greater than 255, then RM_CMD_BANK_SWITCH needs to be + * sent first. Else, skip the header i.e. xfer[0]. + */ + int xfer_start_idx = (addr > 0xff) ? 0 : 1; + xfer_count -= xfer_start_idx; + + ret = i2c_transfer(client->adapter, &xfer[xfer_start_idx], xfer_count); + if (likely(ret == xfer_count)) + return 0; + + return ret < 0 ? ret : -EIO; +} + +static int raydium_i2c_send(struct i2c_client *client, + u32 addr, const void *data, size_t len) +{ + int tries = 0; + int error; + u8 *tx_buf; + u8 reg_addr = addr & 0xff; + + tx_buf = kmalloc(len + 1, GFP_KERNEL); + if (!tx_buf) return -ENOMEM; - buf[0] = addr; - memcpy(buf + 1, data, len); + tx_buf[0] = reg_addr; + memcpy(tx_buf + 1, data, len); do { - ret = i2c_master_send(client, buf, len + 1); - if (likely(ret == len + 1)) - break; + struct raydium_bank_switch_header header = { + .cmd = RM_CMD_BANK_SWITCH, + .be_addr = cpu_to_be32(addr), + }; - msleep(20); + /* + * Perform as a single i2c_transfer transaction to ensure that + * no other I2C transactions are initiated on the bus to any + * other device in between. Initiating transacations to other + * devices after RM_CMD_BANK_SWITCH is sent is known to cause + * issues. This is also why regmap infrastructure cannot be used + * for this driver. Regmap handles page(bank) switch and reads + * as separate i2c_transfer() operations. This can result in + * problems if the Raydium device is on a shared I2C bus. + */ + struct i2c_msg xfer[] = { + { + .addr = client->addr, + .len = sizeof(header), + .buf = (u8 *)&header, + }, + { + .addr = client->addr, + .len = len + 1, + .buf = tx_buf, + }, + }; + + error = raydium_i2c_xfer(client, addr, xfer, ARRAY_SIZE(xfer)); + if (likely(!error)) + goto out; + + msleep(RM_RETRY_DELAY_MS); } while (++tries < RM_MAX_RETRIES); - kfree(buf); - - if (unlikely(ret != len + 1)) { - if (ret >= 0) - ret = -EIO; - dev_err(&client->dev, "%s failed: %d\n", __func__, ret); - return ret; - } - - return 0; + dev_err(&client->dev, "%s failed: %d\n", __func__, error); +out: + kfree(tx_buf); + return error; } static int raydium_i2c_read(struct i2c_client *client, - u8 addr, void *data, size_t len) + u32 addr, void *data, size_t len) { - struct i2c_msg xfer[] = { - { - .addr = client->addr, - .len = 1, - .buf = &addr, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = data, - } - }; - int ret; - - ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer)); - if (unlikely(ret != ARRAY_SIZE(xfer))) - return ret < 0 ? ret : -EIO; - - return 0; -} - -static int raydium_i2c_read_message(struct i2c_client *client, - u32 addr, void *data, size_t len) -{ - __be32 be_addr; - size_t xfer_len; int error; while (len) { - xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE); + u8 reg_addr = addr & 0xff; + struct raydium_bank_switch_header header = { + .cmd = RM_CMD_BANK_SWITCH, + .be_addr = cpu_to_be32(addr), + }; + size_t xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE); - be_addr = cpu_to_be32(addr); + /* + * Perform as a single i2c_transfer transaction to ensure that + * no other I2C transactions are initiated on the bus to any + * other device in between. Initiating transacations to other + * devices after RM_CMD_BANK_SWITCH is sent is known to cause + * issues. This is also why regmap infrastructure cannot be used + * for this driver. Regmap handles page(bank) switch and writes + * as separate i2c_transfer() operations. This can result in + * problems if the Raydium device is on a shared I2C bus. + */ + struct i2c_msg xfer[] = { + { + .addr = client->addr, + .len = sizeof(header), + .buf = (u8 *)&header, + }, + { + .addr = client->addr, + .len = 1, + .buf = ®_addr, + }, + { + .addr = client->addr, + .len = xfer_len, + .buf = data, + .flags = I2C_M_RD, + } + }; - error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH, - &be_addr, sizeof(be_addr)); - if (!error) - error = raydium_i2c_read(client, addr & 0xff, - data, xfer_len); - if (error) + error = raydium_i2c_xfer(client, addr, xfer, ARRAY_SIZE(xfer)); + if (unlikely(error)) return error; len -= xfer_len; @@ -232,27 +275,13 @@ return 0; } -static int raydium_i2c_send_message(struct i2c_client *client, - u32 addr, const void *data, size_t len) -{ - __be32 be_addr = cpu_to_be32(addr); - int error; - - error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH, - &be_addr, sizeof(be_addr)); - if (!error) - error = raydium_i2c_send(client, addr & 0xff, data, len); - - return error; -} - static int raydium_i2c_sw_reset(struct i2c_client *client) { const u8 soft_rst_cmd = 0x01; int error; - error = raydium_i2c_send_message(client, RM_RESET_MSG_ADDR, - &soft_rst_cmd, sizeof(soft_rst_cmd)); + error = raydium_i2c_send(client, RM_RESET_MSG_ADDR, &soft_rst_cmd, + sizeof(soft_rst_cmd)); if (error) { dev_err(&client->dev, "software reset failed: %d\n", error); return error; @@ -304,9 +333,8 @@ if (error) continue; - error = raydium_i2c_read_message(client, - le32_to_cpu(query_bank_addr), - &ts->info, sizeof(ts->info)); + error = raydium_i2c_read(client, le32_to_cpu(query_bank_addr), + &ts->info, sizeof(ts->info)); if (error) continue; @@ -844,8 +872,8 @@ if (ts->boot_mode != RAYDIUM_TS_MAIN) goto out; - error = raydium_i2c_read_message(ts->client, ts->data_bank_addr, - ts->report_data, ts->pkg_size); + error = raydium_i2c_read(ts->client, ts->data_bank_addr, + ts->report_data, ts->pkg_size); if (error) goto out; -- Gitblit v1.6.2