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