| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| |
| #ifndef _REALTEK_PSE_MCU_H |
| #define _REALTEK_PSE_MCU_H |
| |
| #include <linux/mutex.h> |
| #include <linux/pse-pd/pse.h> |
| #include <linux/types.h> |
| |
| /* |
| * Time the MCU itself needs between accepting a request and having a |
| * response ready. These are properties of the MCU firmware, not of the |
| * underlying transport: the core paces transactions by RTPSE_MCU_RESPONSE_MS |
| * and both transports size their per-transaction recv ceiling from |
| * RTPSE_MCU_RESPONSE_MAX_MS, since some commands are documented as |
| * needing up to ~1s to produce a reply. |
| */ |
| #define RTPSE_MCU_RESPONSE_MS 25 |
| #define RTPSE_MCU_RESPONSE_MAX_MS 1000 |
| |
| /* |
| * Total time to keep retrying the first MCU read at probe, and the pause |
| * between attempts. Right after reset-gpios is deasserted the MCU may not |
| * answer on the bus yet; give it a bounded window to come up before |
| * declaring the probe failed. |
| */ |
| #define RTPSE_MCU_BOOT_TIMEOUT_MS 3000 |
| #define RTPSE_MCU_BOOT_RETRY_MS 100 |
| |
| #define RTPSE_MCU_MSG_SIZE 12 |
| |
| struct rtpse_mcu_msg { |
| u8 opcode; |
| u8 seq_num; |
| u8 payload[9]; |
| u8 checksum; |
| } __packed; |
| |
| /* |
| * MCU status opcodes (seen on the Gen1 dialect; Gen2 never emits them). |
| * INCOMPLETE/BAD_CSUM are terminal; NOT_READY is transient. |
| */ |
| #define RTPSE_MCU_OPCODE_INCOMPLETE 0xfd /* -EBADE */ |
| #define RTPSE_MCU_OPCODE_BAD_CSUM 0xfe /* -EBADMSG */ |
| #define RTPSE_MCU_OPCODE_NOT_READY 0xff /* -EAGAIN */ |
| |
| /* |
| * A polling transport can stop here: the reply to this request (opcode and |
| * seq_num) or a terminal error. The seq_num rejects a stale normal reply; the |
| * terminal errors match unconditionally, as a request the MCU couldn't parse |
| * carries no seq_num to correlate against. |
| */ |
| static inline bool rtpse_mcu_resp_is_final(const struct rtpse_mcu_msg *req, |
| const struct rtpse_mcu_msg *resp) |
| { |
| return (resp->opcode == req->opcode && resp->seq_num == req->seq_num) || |
| resp->opcode == RTPSE_MCU_OPCODE_INCOMPLETE || |
| resp->opcode == RTPSE_MCU_OPCODE_BAD_CSUM; |
| } |
| |
| /* Opaque to transports; defined in realtek-pse-mcu-core.c. */ |
| struct rtpse_mcu_dialect; |
| struct rtpse_mcu_chip_info; |
| struct rtpse_mcu_ctrl; |
| |
| /* Per-compatible match data (the of_match .data). */ |
| struct rtpse_mcu_match_data { |
| const struct rtpse_mcu_dialect *dialect; |
| bool native_i2c; /* raw-I2C framing (vs SMBus); I2C transport only */ |
| }; |
| |
| struct rtpse_mcu_transport_ops { |
| int (*send)(struct rtpse_mcu_ctrl *pse, const struct rtpse_mcu_msg *req); |
| int (*recv)(struct rtpse_mcu_ctrl *pse, const struct rtpse_mcu_msg *req, |
| struct rtpse_mcu_msg *resp); |
| }; |
| |
| struct rtpse_mcu_ctrl { |
| struct device *dev; |
| struct pse_controller_dev pcdev; |
| struct mutex mutex; /* serializes MCU request/response transactions */ |
| const struct rtpse_mcu_dialect *dialect; |
| const struct rtpse_mcu_chip_info *chip; |
| const struct rtpse_mcu_transport_ops *transport; |
| u8 seq; /* rolling request seq_num, echoed by the MCU */ |
| }; |
| |
| int rtpse_mcu_register(struct rtpse_mcu_ctrl *pse); |
| |
| extern const struct rtpse_mcu_match_data rtpse_mcu_gen1_data; |
| extern const struct rtpse_mcu_match_data rtpse_mcu_gen2_data; |
| extern const struct rtpse_mcu_match_data rtpse_mcu_gen2_i2c_data; |
| |
| #endif |