mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-23 09:42:19 +03:00
Add IO Expander support in CDI Dev to control the FRSYNC multiplexer with the speicific platform Bug 3582660 Change-Id: I3ee376e7a0bccabcfa16efb228879d4df0d65748 Signed-off-by: Junghyun Kim <juskim@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2727256 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2824551 Reviewed-by: Frank Chen <frankc@nvidia.com> Reviewed-by: Shiva Dubey <sdubey@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
123 lines
2.6 KiB
C
123 lines
2.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
|
|
#ifndef __CDI_TCA9539_PRIV_H__
|
|
#define __CDI_TCA9539_PRIV_H__
|
|
|
|
/* i2c payload size is only 12 bit */
|
|
#define MAX_MSG_SIZE (0xFFF - 1)
|
|
|
|
struct tca9539_priv {
|
|
struct i2c_adapter *adap;
|
|
int bus;
|
|
u32 addr;
|
|
u32 reg_len;
|
|
u32 dat_len;
|
|
u8 init_val[12];
|
|
u32 power_port;
|
|
bool enable;
|
|
};
|
|
|
|
static int tca9539_raw_wr(
|
|
struct device *dev, struct tca9539_priv *tca9539, unsigned int offset, u8 val)
|
|
{
|
|
int ret = -ENODEV;
|
|
u8 *buf_start = NULL;
|
|
struct i2c_msg *i2cmsg;
|
|
unsigned int num_msgs = 0, total_size, i;
|
|
u8 data[3];
|
|
size_t size = 1;
|
|
|
|
dev_dbg(dev, "%s\n", __func__);
|
|
|
|
if (tca9539->reg_len == 2) {
|
|
data[0] = (u8)((offset >> 8) & 0xff);
|
|
data[1] = (u8)(offset & 0xff);
|
|
data[2] = val;
|
|
size += 2;
|
|
} else if (tca9539->reg_len == 1) {
|
|
data[0] = (u8)(offset & 0xff);
|
|
data[1] = val;
|
|
size += 1;
|
|
} else if ((tca9539->reg_len == 0) ||
|
|
(tca9539->reg_len > 3)) {
|
|
return 0;
|
|
}
|
|
|
|
num_msgs = size / MAX_MSG_SIZE;
|
|
num_msgs += (size % MAX_MSG_SIZE) ? 1 : 0;
|
|
|
|
i2cmsg = kzalloc((sizeof(struct i2c_msg)*num_msgs), GFP_KERNEL);
|
|
if (!i2cmsg) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
buf_start = data;
|
|
total_size = size;
|
|
|
|
dev_dbg(dev, "%s: num_msgs: %d\n", __func__, num_msgs);
|
|
for (i = 0; i < num_msgs; i++) {
|
|
i2cmsg[i].addr = tca9539->addr;
|
|
i2cmsg[i].buf = (__u8 *)buf_start;
|
|
|
|
if (i > 0)
|
|
i2cmsg[i].flags = I2C_M_NOSTART;
|
|
else
|
|
i2cmsg[i].flags = 0;
|
|
|
|
if (total_size > MAX_MSG_SIZE) {
|
|
i2cmsg[i].len = MAX_MSG_SIZE;
|
|
buf_start += MAX_MSG_SIZE;
|
|
total_size -= MAX_MSG_SIZE;
|
|
} else {
|
|
i2cmsg[i].len = total_size;
|
|
}
|
|
dev_dbg(dev, "%s: addr:%x buf:%p, flags:%u len:%u\n",
|
|
__func__, i2cmsg[i].addr, (void *)i2cmsg[i].buf,
|
|
i2cmsg[i].flags, i2cmsg[i].len);
|
|
}
|
|
|
|
ret = i2c_transfer(tca9539->adap, i2cmsg, num_msgs);
|
|
if (ret > 0)
|
|
ret = 0;
|
|
|
|
kfree(i2cmsg);
|
|
return ret;
|
|
}
|
|
|
|
static int tca9539_raw_rd(
|
|
struct device *dev, struct tca9539_priv *tca9539, unsigned int offset, u8 *val)
|
|
{
|
|
int ret = -ENODEV;
|
|
u8 data[2];
|
|
size_t size = 1;
|
|
struct i2c_msg i2cmsg[2];
|
|
|
|
dev_dbg(dev, "%s\n", __func__);
|
|
|
|
if (tca9539->reg_len == 2) {
|
|
data[0] = (u8)((offset >> 8) & 0xff);
|
|
data[1] = (u8)(offset & 0xff);
|
|
} else if (tca9539->reg_len == 1)
|
|
data[0] = (u8)(offset & 0xff);
|
|
|
|
i2cmsg[0].addr = tca9539->addr;
|
|
i2cmsg[0].len = tca9539->reg_len;
|
|
i2cmsg[0].buf = (__u8 *)data;
|
|
i2cmsg[0].flags = I2C_M_NOSTART;
|
|
|
|
i2cmsg[1].addr = tca9539->addr;
|
|
i2cmsg[1].flags = I2C_M_RD;
|
|
i2cmsg[1].len = size;
|
|
i2cmsg[1].buf = (__u8 *)val;
|
|
|
|
ret = i2c_transfer(tca9539->adap, i2cmsg, 2);
|
|
if (ret > 0)
|
|
ret = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* __CDI_TCA9539_PRIV_H__ */
|
|
|