Files
linux-nv-oot/drivers/media/platform/tegra/cdi/cdi-tca-priv.h
Junghyun Kim 9269dac3ec drivers: media: CDI: Add IO Expander support
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>
2022-12-13 06:27:42 -08:00

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__ */