// SPDX-License-Identifier: GPL-2.0 /* SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. * All rights reserved. * * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ #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; u32 fsync_ctrl_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->dat_len != 1) return -EINVAL; if (tca9539->reg_len != 1) return -EINVAL; data[0] = (u8)(offset & 0xff); data[1] = val; size += 1; 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->dat_len != 1) return -EINVAL; if (tca9539->reg_len != 1) return -EINVAL; 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__ */