18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * X-Gene SLIMpro I2C Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014, Applied Micro Circuits Corporation 68c2ecf20Sopenharmony_ci * Author: Feng Kan <fkan@apm.com> 78c2ecf20Sopenharmony_ci * Author: Hieu Le <hnle@apm.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This driver provides support for X-Gene SLIMpro I2C device access 108c2ecf20Sopenharmony_ci * using the APM X-Gene SLIMpro mailbox driver. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <acpi/pcc.h> 138c2ecf20Sopenharmony_ci#include <linux/acpi.h> 148c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 158c2ecf20Sopenharmony_ci#include <linux/i2c.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/io.h> 188c2ecf20Sopenharmony_ci#include <linux/mailbox_client.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/of.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci#include <linux/version.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define MAILBOX_OP_TIMEOUT 1000 /* Operation time out in ms */ 258c2ecf20Sopenharmony_ci#define MAILBOX_I2C_INDEX 0 268c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_BUS 1 /* Use I2C bus 1 only */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define SMBUS_CMD_LEN 1 298c2ecf20Sopenharmony_ci#define BYTE_DATA 1 308c2ecf20Sopenharmony_ci#define WORD_DATA 2 318c2ecf20Sopenharmony_ci#define BLOCK_DATA 3 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_I2C_PROTOCOL 0 348c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_SMB_PROTOCOL 1 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_READ 0 378c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_WRITE 1 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define IIC_SMB_WITHOUT_DATA_LEN 0 408c2ecf20Sopenharmony_ci#define IIC_SMB_WITH_DATA_LEN 1 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define SLIMPRO_DEBUG_MSG 0 438c2ecf20Sopenharmony_ci#define SLIMPRO_MSG_TYPE_SHIFT 28 448c2ecf20Sopenharmony_ci#define SLIMPRO_DBG_SUBTYPE_I2C1READ 4 458c2ecf20Sopenharmony_ci#define SLIMPRO_DBGMSG_TYPE_SHIFT 24 468c2ecf20Sopenharmony_ci#define SLIMPRO_DBGMSG_TYPE_MASK 0x0F000000U 478c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_DEV_SHIFT 23 488c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_DEV_MASK 0x00800000U 498c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_DEVID_SHIFT 13 508c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_DEVID_MASK 0x007FE000U 518c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_RW_SHIFT 12 528c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_RW_MASK 0x00001000U 538c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_PROTO_SHIFT 11 548c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_PROTO_MASK 0x00000800U 558c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_ADDRLEN_SHIFT 8 568c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_ADDRLEN_MASK 0x00000700U 578c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_DATALEN_SHIFT 0 588c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_DATALEN_MASK 0x000000FFU 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* 618c2ecf20Sopenharmony_ci * SLIMpro I2C message encode 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * dev - Controller number (0-based) 648c2ecf20Sopenharmony_ci * chip - I2C chip address 658c2ecf20Sopenharmony_ci * op - SLIMPRO_IIC_READ or SLIMPRO_IIC_WRITE 668c2ecf20Sopenharmony_ci * proto - SLIMPRO_IIC_SMB_PROTOCOL or SLIMPRO_IIC_I2C_PROTOCOL 678c2ecf20Sopenharmony_ci * addrlen - Length of the address field 688c2ecf20Sopenharmony_ci * datalen - Length of the data field 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_ENCODE_MSG(dev, chip, op, proto, addrlen, datalen) \ 718c2ecf20Sopenharmony_ci ((SLIMPRO_DEBUG_MSG << SLIMPRO_MSG_TYPE_SHIFT) | \ 728c2ecf20Sopenharmony_ci ((SLIMPRO_DBG_SUBTYPE_I2C1READ << SLIMPRO_DBGMSG_TYPE_SHIFT) & \ 738c2ecf20Sopenharmony_ci SLIMPRO_DBGMSG_TYPE_MASK) | \ 748c2ecf20Sopenharmony_ci ((dev << SLIMPRO_IIC_DEV_SHIFT) & SLIMPRO_IIC_DEV_MASK) | \ 758c2ecf20Sopenharmony_ci ((chip << SLIMPRO_IIC_DEVID_SHIFT) & SLIMPRO_IIC_DEVID_MASK) | \ 768c2ecf20Sopenharmony_ci ((op << SLIMPRO_IIC_RW_SHIFT) & SLIMPRO_IIC_RW_MASK) | \ 778c2ecf20Sopenharmony_ci ((proto << SLIMPRO_IIC_PROTO_SHIFT) & SLIMPRO_IIC_PROTO_MASK) | \ 788c2ecf20Sopenharmony_ci ((addrlen << SLIMPRO_IIC_ADDRLEN_SHIFT) & SLIMPRO_IIC_ADDRLEN_MASK) | \ 798c2ecf20Sopenharmony_ci ((datalen << SLIMPRO_IIC_DATALEN_SHIFT) & SLIMPRO_IIC_DATALEN_MASK)) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define SLIMPRO_MSG_TYPE(v) (((v) & 0xF0000000) >> 28) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* 848c2ecf20Sopenharmony_ci * Encode for upper address for block data 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_ENCODE_FLAG_BUFADDR 0x80000000 878c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_ENCODE_FLAG_WITH_DATA_LEN(a) ((u32) (((a) << 30) \ 888c2ecf20Sopenharmony_ci & 0x40000000)) 898c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_ENCODE_UPPER_BUFADDR(a) ((u32) (((a) >> 12) \ 908c2ecf20Sopenharmony_ci & 0x3FF00000)) 918c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_ENCODE_ADDR(a) ((a) & 0x000FFFFF) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define SLIMPRO_IIC_MSG_DWORD_COUNT 3 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* PCC related defines */ 968c2ecf20Sopenharmony_ci#define PCC_SIGNATURE 0x50424300 978c2ecf20Sopenharmony_ci#define PCC_STS_CMD_COMPLETE BIT(0) 988c2ecf20Sopenharmony_ci#define PCC_STS_SCI_DOORBELL BIT(1) 998c2ecf20Sopenharmony_ci#define PCC_STS_ERR BIT(2) 1008c2ecf20Sopenharmony_ci#define PCC_STS_PLAT_NOTIFY BIT(3) 1018c2ecf20Sopenharmony_ci#define PCC_CMD_GENERATE_DB_INT BIT(15) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistruct slimpro_i2c_dev { 1048c2ecf20Sopenharmony_ci struct i2c_adapter adapter; 1058c2ecf20Sopenharmony_ci struct device *dev; 1068c2ecf20Sopenharmony_ci struct mbox_chan *mbox_chan; 1078c2ecf20Sopenharmony_ci struct mbox_client mbox_client; 1088c2ecf20Sopenharmony_ci int mbox_idx; 1098c2ecf20Sopenharmony_ci struct completion rd_complete; 1108c2ecf20Sopenharmony_ci u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* dma_buffer[0] is used for length */ 1118c2ecf20Sopenharmony_ci u32 *resp_msg; 1128c2ecf20Sopenharmony_ci phys_addr_t comm_base_addr; 1138c2ecf20Sopenharmony_ci void *pcc_comm_addr; 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define to_slimpro_i2c_dev(cl) \ 1178c2ecf20Sopenharmony_ci container_of(cl, struct slimpro_i2c_dev, mbox_client) 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cienum slimpro_i2c_version { 1208c2ecf20Sopenharmony_ci XGENE_SLIMPRO_I2C_V1 = 0, 1218c2ecf20Sopenharmony_ci XGENE_SLIMPRO_I2C_V2 = 1, 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* 1258c2ecf20Sopenharmony_ci * This function tests and clears a bitmask then returns its old value 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistatic u16 xgene_word_tst_and_clr(u16 *addr, u16 mask) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci u16 ret, val; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci val = le16_to_cpu(READ_ONCE(*addr)); 1328c2ecf20Sopenharmony_ci ret = val & mask; 1338c2ecf20Sopenharmony_ci val &= ~mask; 1348c2ecf20Sopenharmony_ci WRITE_ONCE(*addr, cpu_to_le16(val)); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return ret; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic void slimpro_i2c_rx_cb(struct mbox_client *cl, void *mssg) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct slimpro_i2c_dev *ctx = to_slimpro_i2c_dev(cl); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * Response message format: 1458c2ecf20Sopenharmony_ci * mssg[0] is the return code of the operation 1468c2ecf20Sopenharmony_ci * mssg[1] is the first data word 1478c2ecf20Sopenharmony_ci * mssg[2] is NOT used 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci if (ctx->resp_msg) 1508c2ecf20Sopenharmony_ci *ctx->resp_msg = ((u32 *)mssg)[1]; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (ctx->mbox_client.tx_block) 1538c2ecf20Sopenharmony_ci complete(&ctx->rd_complete); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void slimpro_i2c_pcc_rx_cb(struct mbox_client *cl, void *msg) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct slimpro_i2c_dev *ctx = to_slimpro_i2c_dev(cl); 1598c2ecf20Sopenharmony_ci struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Check if platform sends interrupt */ 1628c2ecf20Sopenharmony_ci if (!xgene_word_tst_and_clr(&generic_comm_base->status, 1638c2ecf20Sopenharmony_ci PCC_STS_SCI_DOORBELL)) 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (xgene_word_tst_and_clr(&generic_comm_base->status, 1678c2ecf20Sopenharmony_ci PCC_STS_CMD_COMPLETE)) { 1688c2ecf20Sopenharmony_ci msg = generic_comm_base + 1; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Response message msg[1] contains the return value. */ 1718c2ecf20Sopenharmony_ci if (ctx->resp_msg) 1728c2ecf20Sopenharmony_ci *ctx->resp_msg = ((u32 *)msg)[1]; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci complete(&ctx->rd_complete); 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic void slimpro_i2c_pcc_tx_prepare(struct slimpro_i2c_dev *ctx, u32 *msg) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr; 1818c2ecf20Sopenharmony_ci u32 *ptr = (void *)(generic_comm_base + 1); 1828c2ecf20Sopenharmony_ci u16 status; 1838c2ecf20Sopenharmony_ci int i; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci WRITE_ONCE(generic_comm_base->signature, 1868c2ecf20Sopenharmony_ci cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx)); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci WRITE_ONCE(generic_comm_base->command, 1898c2ecf20Sopenharmony_ci cpu_to_le16(SLIMPRO_MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INT)); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci status = le16_to_cpu(READ_ONCE(generic_comm_base->status)); 1928c2ecf20Sopenharmony_ci status &= ~PCC_STS_CMD_COMPLETE; 1938c2ecf20Sopenharmony_ci WRITE_ONCE(generic_comm_base->status, cpu_to_le16(status)); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* Copy the message to the PCC comm space */ 1968c2ecf20Sopenharmony_ci for (i = 0; i < SLIMPRO_IIC_MSG_DWORD_COUNT; i++) 1978c2ecf20Sopenharmony_ci WRITE_ONCE(ptr[i], cpu_to_le32(msg[i])); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int start_i2c_msg_xfer(struct slimpro_i2c_dev *ctx) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci if (ctx->mbox_client.tx_block || !acpi_disabled) { 2038c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&ctx->rd_complete, 2048c2ecf20Sopenharmony_ci msecs_to_jiffies(MAILBOX_OP_TIMEOUT))) 2058c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Check of invalid data or no device */ 2098c2ecf20Sopenharmony_ci if (*ctx->resp_msg == 0xffffffff) 2108c2ecf20Sopenharmony_ci return -ENODEV; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int slimpro_i2c_send_msg(struct slimpro_i2c_dev *ctx, 2168c2ecf20Sopenharmony_ci u32 *msg, 2178c2ecf20Sopenharmony_ci u32 *data) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci int rc; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ctx->resp_msg = data; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (!acpi_disabled) { 2248c2ecf20Sopenharmony_ci reinit_completion(&ctx->rd_complete); 2258c2ecf20Sopenharmony_ci slimpro_i2c_pcc_tx_prepare(ctx, msg); 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci rc = mbox_send_message(ctx->mbox_chan, msg); 2298c2ecf20Sopenharmony_ci if (rc < 0) 2308c2ecf20Sopenharmony_ci goto err; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci rc = start_i2c_msg_xfer(ctx); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cierr: 2358c2ecf20Sopenharmony_ci if (!acpi_disabled) 2368c2ecf20Sopenharmony_ci mbox_chan_txdone(ctx->mbox_chan, 0); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci ctx->resp_msg = NULL; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return rc; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int slimpro_i2c_rd(struct slimpro_i2c_dev *ctx, u32 chip, 2448c2ecf20Sopenharmony_ci u32 addr, u32 addrlen, u32 protocol, 2458c2ecf20Sopenharmony_ci u32 readlen, u32 *data) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci u32 msg[3]; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, 2508c2ecf20Sopenharmony_ci SLIMPRO_IIC_READ, protocol, addrlen, readlen); 2518c2ecf20Sopenharmony_ci msg[1] = SLIMPRO_IIC_ENCODE_ADDR(addr); 2528c2ecf20Sopenharmony_ci msg[2] = 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return slimpro_i2c_send_msg(ctx, msg, data); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic int slimpro_i2c_wr(struct slimpro_i2c_dev *ctx, u32 chip, 2588c2ecf20Sopenharmony_ci u32 addr, u32 addrlen, u32 protocol, u32 writelen, 2598c2ecf20Sopenharmony_ci u32 data) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci u32 msg[3]; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, 2648c2ecf20Sopenharmony_ci SLIMPRO_IIC_WRITE, protocol, addrlen, writelen); 2658c2ecf20Sopenharmony_ci msg[1] = SLIMPRO_IIC_ENCODE_ADDR(addr); 2668c2ecf20Sopenharmony_ci msg[2] = data; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return slimpro_i2c_send_msg(ctx, msg, msg); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int slimpro_i2c_blkrd(struct slimpro_i2c_dev *ctx, u32 chip, u32 addr, 2728c2ecf20Sopenharmony_ci u32 addrlen, u32 protocol, u32 readlen, 2738c2ecf20Sopenharmony_ci u32 with_data_len, void *data) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci dma_addr_t paddr; 2768c2ecf20Sopenharmony_ci u32 msg[3]; 2778c2ecf20Sopenharmony_ci int rc; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci paddr = dma_map_single(ctx->dev, ctx->dma_buffer, readlen, DMA_FROM_DEVICE); 2808c2ecf20Sopenharmony_ci if (dma_mapping_error(ctx->dev, paddr)) { 2818c2ecf20Sopenharmony_ci dev_err(&ctx->adapter.dev, "Error in mapping dma buffer %p\n", 2828c2ecf20Sopenharmony_ci ctx->dma_buffer); 2838c2ecf20Sopenharmony_ci return -ENOMEM; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, SLIMPRO_IIC_READ, 2878c2ecf20Sopenharmony_ci protocol, addrlen, readlen); 2888c2ecf20Sopenharmony_ci msg[1] = SLIMPRO_IIC_ENCODE_FLAG_BUFADDR | 2898c2ecf20Sopenharmony_ci SLIMPRO_IIC_ENCODE_FLAG_WITH_DATA_LEN(with_data_len) | 2908c2ecf20Sopenharmony_ci SLIMPRO_IIC_ENCODE_UPPER_BUFADDR(paddr) | 2918c2ecf20Sopenharmony_ci SLIMPRO_IIC_ENCODE_ADDR(addr); 2928c2ecf20Sopenharmony_ci msg[2] = (u32)paddr; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci rc = slimpro_i2c_send_msg(ctx, msg, msg); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Copy to destination */ 2978c2ecf20Sopenharmony_ci memcpy(data, ctx->dma_buffer, readlen); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci dma_unmap_single(ctx->dev, paddr, readlen, DMA_FROM_DEVICE); 3008c2ecf20Sopenharmony_ci return rc; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int slimpro_i2c_blkwr(struct slimpro_i2c_dev *ctx, u32 chip, 3048c2ecf20Sopenharmony_ci u32 addr, u32 addrlen, u32 protocol, u32 writelen, 3058c2ecf20Sopenharmony_ci void *data) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci dma_addr_t paddr; 3088c2ecf20Sopenharmony_ci u32 msg[3]; 3098c2ecf20Sopenharmony_ci int rc; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (writelen > I2C_SMBUS_BLOCK_MAX) 3128c2ecf20Sopenharmony_ci return -EINVAL; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci memcpy(ctx->dma_buffer, data, writelen); 3158c2ecf20Sopenharmony_ci paddr = dma_map_single(ctx->dev, ctx->dma_buffer, writelen, 3168c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3178c2ecf20Sopenharmony_ci if (dma_mapping_error(ctx->dev, paddr)) { 3188c2ecf20Sopenharmony_ci dev_err(&ctx->adapter.dev, "Error in mapping dma buffer %p\n", 3198c2ecf20Sopenharmony_ci ctx->dma_buffer); 3208c2ecf20Sopenharmony_ci return -ENOMEM; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, SLIMPRO_IIC_WRITE, 3248c2ecf20Sopenharmony_ci protocol, addrlen, writelen); 3258c2ecf20Sopenharmony_ci msg[1] = SLIMPRO_IIC_ENCODE_FLAG_BUFADDR | 3268c2ecf20Sopenharmony_ci SLIMPRO_IIC_ENCODE_UPPER_BUFADDR(paddr) | 3278c2ecf20Sopenharmony_ci SLIMPRO_IIC_ENCODE_ADDR(addr); 3288c2ecf20Sopenharmony_ci msg[2] = (u32)paddr; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (ctx->mbox_client.tx_block) 3318c2ecf20Sopenharmony_ci reinit_completion(&ctx->rd_complete); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci rc = slimpro_i2c_send_msg(ctx, msg, msg); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci dma_unmap_single(ctx->dev, paddr, writelen, DMA_TO_DEVICE); 3368c2ecf20Sopenharmony_ci return rc; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic int xgene_slimpro_i2c_xfer(struct i2c_adapter *adap, u16 addr, 3408c2ecf20Sopenharmony_ci unsigned short flags, char read_write, 3418c2ecf20Sopenharmony_ci u8 command, int size, 3428c2ecf20Sopenharmony_ci union i2c_smbus_data *data) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct slimpro_i2c_dev *ctx = i2c_get_adapdata(adap); 3458c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 3468c2ecf20Sopenharmony_ci u32 val; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci switch (size) { 3498c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE: 3508c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) { 3518c2ecf20Sopenharmony_ci ret = slimpro_i2c_rd(ctx, addr, 0, 0, 3528c2ecf20Sopenharmony_ci SLIMPRO_IIC_SMB_PROTOCOL, 3538c2ecf20Sopenharmony_ci BYTE_DATA, &val); 3548c2ecf20Sopenharmony_ci data->byte = val; 3558c2ecf20Sopenharmony_ci } else { 3568c2ecf20Sopenharmony_ci ret = slimpro_i2c_wr(ctx, addr, command, SMBUS_CMD_LEN, 3578c2ecf20Sopenharmony_ci SLIMPRO_IIC_SMB_PROTOCOL, 3588c2ecf20Sopenharmony_ci 0, 0); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE_DATA: 3628c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) { 3638c2ecf20Sopenharmony_ci ret = slimpro_i2c_rd(ctx, addr, command, SMBUS_CMD_LEN, 3648c2ecf20Sopenharmony_ci SLIMPRO_IIC_SMB_PROTOCOL, 3658c2ecf20Sopenharmony_ci BYTE_DATA, &val); 3668c2ecf20Sopenharmony_ci data->byte = val; 3678c2ecf20Sopenharmony_ci } else { 3688c2ecf20Sopenharmony_ci val = data->byte; 3698c2ecf20Sopenharmony_ci ret = slimpro_i2c_wr(ctx, addr, command, SMBUS_CMD_LEN, 3708c2ecf20Sopenharmony_ci SLIMPRO_IIC_SMB_PROTOCOL, 3718c2ecf20Sopenharmony_ci BYTE_DATA, val); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci case I2C_SMBUS_WORD_DATA: 3758c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) { 3768c2ecf20Sopenharmony_ci ret = slimpro_i2c_rd(ctx, addr, command, SMBUS_CMD_LEN, 3778c2ecf20Sopenharmony_ci SLIMPRO_IIC_SMB_PROTOCOL, 3788c2ecf20Sopenharmony_ci WORD_DATA, &val); 3798c2ecf20Sopenharmony_ci data->word = val; 3808c2ecf20Sopenharmony_ci } else { 3818c2ecf20Sopenharmony_ci val = data->word; 3828c2ecf20Sopenharmony_ci ret = slimpro_i2c_wr(ctx, addr, command, SMBUS_CMD_LEN, 3838c2ecf20Sopenharmony_ci SLIMPRO_IIC_SMB_PROTOCOL, 3848c2ecf20Sopenharmony_ci WORD_DATA, val); 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_DATA: 3888c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) { 3898c2ecf20Sopenharmony_ci ret = slimpro_i2c_blkrd(ctx, addr, command, 3908c2ecf20Sopenharmony_ci SMBUS_CMD_LEN, 3918c2ecf20Sopenharmony_ci SLIMPRO_IIC_SMB_PROTOCOL, 3928c2ecf20Sopenharmony_ci I2C_SMBUS_BLOCK_MAX + 1, 3938c2ecf20Sopenharmony_ci IIC_SMB_WITH_DATA_LEN, 3948c2ecf20Sopenharmony_ci &data->block[0]); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci } else { 3978c2ecf20Sopenharmony_ci ret = slimpro_i2c_blkwr(ctx, addr, command, 3988c2ecf20Sopenharmony_ci SMBUS_CMD_LEN, 3998c2ecf20Sopenharmony_ci SLIMPRO_IIC_SMB_PROTOCOL, 4008c2ecf20Sopenharmony_ci data->block[0] + 1, 4018c2ecf20Sopenharmony_ci &data->block[0]); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci case I2C_SMBUS_I2C_BLOCK_DATA: 4058c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) { 4068c2ecf20Sopenharmony_ci ret = slimpro_i2c_blkrd(ctx, addr, 4078c2ecf20Sopenharmony_ci command, 4088c2ecf20Sopenharmony_ci SMBUS_CMD_LEN, 4098c2ecf20Sopenharmony_ci SLIMPRO_IIC_I2C_PROTOCOL, 4108c2ecf20Sopenharmony_ci I2C_SMBUS_BLOCK_MAX, 4118c2ecf20Sopenharmony_ci IIC_SMB_WITHOUT_DATA_LEN, 4128c2ecf20Sopenharmony_ci &data->block[1]); 4138c2ecf20Sopenharmony_ci } else { 4148c2ecf20Sopenharmony_ci ret = slimpro_i2c_blkwr(ctx, addr, command, 4158c2ecf20Sopenharmony_ci SMBUS_CMD_LEN, 4168c2ecf20Sopenharmony_ci SLIMPRO_IIC_I2C_PROTOCOL, 4178c2ecf20Sopenharmony_ci data->block[0], 4188c2ecf20Sopenharmony_ci &data->block[1]); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci default: 4228c2ecf20Sopenharmony_ci break; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci return ret; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/* 4288c2ecf20Sopenharmony_ci* Return list of supported functionality. 4298c2ecf20Sopenharmony_ci*/ 4308c2ecf20Sopenharmony_cistatic u32 xgene_slimpro_i2c_func(struct i2c_adapter *adapter) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci return I2C_FUNC_SMBUS_BYTE | 4338c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BYTE_DATA | 4348c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WORD_DATA | 4358c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BLOCK_DATA | 4368c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_I2C_BLOCK; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic const struct i2c_algorithm xgene_slimpro_i2c_algorithm = { 4408c2ecf20Sopenharmony_ci .smbus_xfer = xgene_slimpro_i2c_xfer, 4418c2ecf20Sopenharmony_ci .functionality = xgene_slimpro_i2c_func, 4428c2ecf20Sopenharmony_ci}; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int xgene_slimpro_i2c_probe(struct platform_device *pdev) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct slimpro_i2c_dev *ctx; 4478c2ecf20Sopenharmony_ci struct i2c_adapter *adapter; 4488c2ecf20Sopenharmony_ci struct mbox_client *cl; 4498c2ecf20Sopenharmony_ci int rc; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 4528c2ecf20Sopenharmony_ci if (!ctx) 4538c2ecf20Sopenharmony_ci return -ENOMEM; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci ctx->dev = &pdev->dev; 4568c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ctx); 4578c2ecf20Sopenharmony_ci cl = &ctx->mbox_client; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* Request mailbox channel */ 4608c2ecf20Sopenharmony_ci cl->dev = &pdev->dev; 4618c2ecf20Sopenharmony_ci init_completion(&ctx->rd_complete); 4628c2ecf20Sopenharmony_ci cl->tx_tout = MAILBOX_OP_TIMEOUT; 4638c2ecf20Sopenharmony_ci cl->knows_txdone = false; 4648c2ecf20Sopenharmony_ci if (acpi_disabled) { 4658c2ecf20Sopenharmony_ci cl->tx_block = true; 4668c2ecf20Sopenharmony_ci cl->rx_callback = slimpro_i2c_rx_cb; 4678c2ecf20Sopenharmony_ci ctx->mbox_chan = mbox_request_channel(cl, MAILBOX_I2C_INDEX); 4688c2ecf20Sopenharmony_ci if (IS_ERR(ctx->mbox_chan)) { 4698c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "i2c mailbox channel request failed\n"); 4708c2ecf20Sopenharmony_ci return PTR_ERR(ctx->mbox_chan); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci } else { 4738c2ecf20Sopenharmony_ci struct acpi_pcct_hw_reduced *cppc_ss; 4748c2ecf20Sopenharmony_ci const struct acpi_device_id *acpi_id; 4758c2ecf20Sopenharmony_ci int version = XGENE_SLIMPRO_I2C_V1; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table, 4788c2ecf20Sopenharmony_ci &pdev->dev); 4798c2ecf20Sopenharmony_ci if (!acpi_id) 4808c2ecf20Sopenharmony_ci return -EINVAL; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci version = (int)acpi_id->driver_data; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (device_property_read_u32(&pdev->dev, "pcc-channel", 4858c2ecf20Sopenharmony_ci &ctx->mbox_idx)) 4868c2ecf20Sopenharmony_ci ctx->mbox_idx = MAILBOX_I2C_INDEX; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci cl->tx_block = false; 4898c2ecf20Sopenharmony_ci cl->rx_callback = slimpro_i2c_pcc_rx_cb; 4908c2ecf20Sopenharmony_ci ctx->mbox_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx); 4918c2ecf20Sopenharmony_ci if (IS_ERR(ctx->mbox_chan)) { 4928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "PCC mailbox channel request failed\n"); 4938c2ecf20Sopenharmony_ci return PTR_ERR(ctx->mbox_chan); 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * The PCC mailbox controller driver should 4988c2ecf20Sopenharmony_ci * have parsed the PCCT (global table of all 4998c2ecf20Sopenharmony_ci * PCC channels) and stored pointers to the 5008c2ecf20Sopenharmony_ci * subspace communication region in con_priv. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci cppc_ss = ctx->mbox_chan->con_priv; 5038c2ecf20Sopenharmony_ci if (!cppc_ss) { 5048c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "PPC subspace not found\n"); 5058c2ecf20Sopenharmony_ci rc = -ENOENT; 5068c2ecf20Sopenharmony_ci goto mbox_err; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (!ctx->mbox_chan->mbox->txdone_irq) { 5108c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "PCC IRQ not supported\n"); 5118c2ecf20Sopenharmony_ci rc = -ENOENT; 5128c2ecf20Sopenharmony_ci goto mbox_err; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* 5168c2ecf20Sopenharmony_ci * This is the shared communication region 5178c2ecf20Sopenharmony_ci * for the OS and Platform to communicate over. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_ci ctx->comm_base_addr = cppc_ss->base_address; 5208c2ecf20Sopenharmony_ci if (ctx->comm_base_addr) { 5218c2ecf20Sopenharmony_ci if (version == XGENE_SLIMPRO_I2C_V2) 5228c2ecf20Sopenharmony_ci ctx->pcc_comm_addr = memremap( 5238c2ecf20Sopenharmony_ci ctx->comm_base_addr, 5248c2ecf20Sopenharmony_ci cppc_ss->length, 5258c2ecf20Sopenharmony_ci MEMREMAP_WT); 5268c2ecf20Sopenharmony_ci else 5278c2ecf20Sopenharmony_ci ctx->pcc_comm_addr = memremap( 5288c2ecf20Sopenharmony_ci ctx->comm_base_addr, 5298c2ecf20Sopenharmony_ci cppc_ss->length, 5308c2ecf20Sopenharmony_ci MEMREMAP_WB); 5318c2ecf20Sopenharmony_ci } else { 5328c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to get PCC comm region\n"); 5338c2ecf20Sopenharmony_ci rc = -ENOENT; 5348c2ecf20Sopenharmony_ci goto mbox_err; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (!ctx->pcc_comm_addr) { 5388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 5398c2ecf20Sopenharmony_ci "Failed to ioremap PCC comm region\n"); 5408c2ecf20Sopenharmony_ci rc = -ENOMEM; 5418c2ecf20Sopenharmony_ci goto mbox_err; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 5458c2ecf20Sopenharmony_ci if (rc) 5468c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Unable to set dma mask\n"); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Setup I2C adapter */ 5498c2ecf20Sopenharmony_ci adapter = &ctx->adapter; 5508c2ecf20Sopenharmony_ci snprintf(adapter->name, sizeof(adapter->name), "MAILBOX I2C"); 5518c2ecf20Sopenharmony_ci adapter->algo = &xgene_slimpro_i2c_algorithm; 5528c2ecf20Sopenharmony_ci adapter->class = I2C_CLASS_HWMON; 5538c2ecf20Sopenharmony_ci adapter->dev.parent = &pdev->dev; 5548c2ecf20Sopenharmony_ci adapter->dev.of_node = pdev->dev.of_node; 5558c2ecf20Sopenharmony_ci ACPI_COMPANION_SET(&adapter->dev, ACPI_COMPANION(&pdev->dev)); 5568c2ecf20Sopenharmony_ci i2c_set_adapdata(adapter, ctx); 5578c2ecf20Sopenharmony_ci rc = i2c_add_adapter(adapter); 5588c2ecf20Sopenharmony_ci if (rc) 5598c2ecf20Sopenharmony_ci goto mbox_err; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Mailbox I2C Adapter registered\n"); 5628c2ecf20Sopenharmony_ci return 0; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cimbox_err: 5658c2ecf20Sopenharmony_ci if (acpi_disabled) 5668c2ecf20Sopenharmony_ci mbox_free_channel(ctx->mbox_chan); 5678c2ecf20Sopenharmony_ci else 5688c2ecf20Sopenharmony_ci pcc_mbox_free_channel(ctx->mbox_chan); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return rc; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic int xgene_slimpro_i2c_remove(struct platform_device *pdev) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct slimpro_i2c_dev *ctx = platform_get_drvdata(pdev); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci i2c_del_adapter(&ctx->adapter); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (acpi_disabled) 5808c2ecf20Sopenharmony_ci mbox_free_channel(ctx->mbox_chan); 5818c2ecf20Sopenharmony_ci else 5828c2ecf20Sopenharmony_ci pcc_mbox_free_channel(ctx->mbox_chan); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic const struct of_device_id xgene_slimpro_i2c_dt_ids[] = { 5888c2ecf20Sopenharmony_ci {.compatible = "apm,xgene-slimpro-i2c" }, 5898c2ecf20Sopenharmony_ci {}, 5908c2ecf20Sopenharmony_ci}; 5918c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, xgene_slimpro_i2c_dt_ids); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 5948c2ecf20Sopenharmony_cistatic const struct acpi_device_id xgene_slimpro_i2c_acpi_ids[] = { 5958c2ecf20Sopenharmony_ci {"APMC0D40", XGENE_SLIMPRO_I2C_V1}, 5968c2ecf20Sopenharmony_ci {"APMC0D8B", XGENE_SLIMPRO_I2C_V2}, 5978c2ecf20Sopenharmony_ci {} 5988c2ecf20Sopenharmony_ci}; 5998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids); 6008c2ecf20Sopenharmony_ci#endif 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic struct platform_driver xgene_slimpro_i2c_driver = { 6038c2ecf20Sopenharmony_ci .probe = xgene_slimpro_i2c_probe, 6048c2ecf20Sopenharmony_ci .remove = xgene_slimpro_i2c_remove, 6058c2ecf20Sopenharmony_ci .driver = { 6068c2ecf20Sopenharmony_ci .name = "xgene-slimpro-i2c", 6078c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(xgene_slimpro_i2c_dt_ids), 6088c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(xgene_slimpro_i2c_acpi_ids) 6098c2ecf20Sopenharmony_ci }, 6108c2ecf20Sopenharmony_ci}; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cimodule_platform_driver(xgene_slimpro_i2c_driver); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("APM X-Gene SLIMpro I2C driver"); 6158c2ecf20Sopenharmony_ciMODULE_AUTHOR("Feng Kan <fkan@apm.com>"); 6168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Hieu Le <hnle@apm.com>"); 6178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 618