mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-03-01 03:13:58 +00:00
575.51.02
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2005-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2005-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "os-interface.h"
|
||||
#include "nv-linux.h"
|
||||
#include "nvi2c.h"
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
|
||||
@@ -286,7 +287,238 @@ void NV_API_CALL nv_i2c_del_adapter(nv_state_t *nv, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
#else // defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
#if NV_SUPPORTS_PLATFORM_DISPLAY_DEVICE
|
||||
static struct i2c_client * nv_i2c_register_client(
|
||||
nv_state_t *nv,
|
||||
NvU32 linuxI2CSwPort,
|
||||
NvU8 address)
|
||||
{
|
||||
nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
|
||||
struct i2c_adapter *i2c_adapter;
|
||||
struct i2c_client *client;
|
||||
int c_index;
|
||||
struct i2c_board_info i2c_dev_info = {
|
||||
.type = "tegra_display",
|
||||
.addr = address,
|
||||
};
|
||||
|
||||
/* Get the adapter using i2c port */
|
||||
i2c_adapter = i2c_get_adapter(linuxI2CSwPort);
|
||||
if (i2c_adapter == NULL)
|
||||
{
|
||||
nv_printf(NV_DBG_ERRORS, "Unable to get i2c adapter for port(%d)",
|
||||
linuxI2CSwPort);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_NEW_CLIENT_DEVICE_PRESENT)
|
||||
client = i2c_new_client_device(i2c_adapter, &i2c_dev_info);
|
||||
#else
|
||||
nv_printf(NV_DBG_ERRORS, "nv_i2c_new_device not present\n");
|
||||
client = NULL;
|
||||
#endif
|
||||
if (client == NULL)
|
||||
{
|
||||
nv_printf(NV_DBG_ERRORS, "Unable to register client for address(0x%x)",
|
||||
address);
|
||||
i2c_put_adapter(i2c_adapter);
|
||||
return NULL;
|
||||
}
|
||||
i2c_put_adapter(i2c_adapter);
|
||||
|
||||
/* Save the Port and i2c client */
|
||||
nvl->i2c_clients[linuxI2CSwPort].port = linuxI2CSwPort;
|
||||
for (c_index = 0; c_index < MAX_CLIENTS_PER_ADAPTER; c_index++)
|
||||
{
|
||||
if (nvl->i2c_clients[linuxI2CSwPort].pOsClient[c_index] == NULL)
|
||||
{
|
||||
nvl->i2c_clients[linuxI2CSwPort].pOsClient[c_index] = client;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
static struct i2c_client *nv_i2c_get_registered_client(
|
||||
nv_state_t *nv,
|
||||
NvU32 linuxI2CSwPort,
|
||||
NvU8 address)
|
||||
{
|
||||
nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
|
||||
int c_index;
|
||||
|
||||
for (c_index = 0; c_index < MAX_CLIENTS_PER_ADAPTER; c_index++)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
|
||||
client = (struct i2c_client *)nvl->i2c_clients[linuxI2CSwPort].pOsClient[c_index];
|
||||
if (client)
|
||||
{
|
||||
if (address == (NvU8)client->addr)
|
||||
{
|
||||
return client;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NV_STATUS NV_API_CALL nv_i2c_transfer(
|
||||
nv_state_t *nv,
|
||||
NvU32 linuxI2CSwPort,
|
||||
NvU8 address,
|
||||
nv_i2c_msg_t *nv_msgs,
|
||||
int num_msgs
|
||||
)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct i2c_msg *msgs;
|
||||
int count;
|
||||
int rc;
|
||||
NV_STATUS status = NV_OK;
|
||||
|
||||
//
|
||||
// RM style client address is 8-bit addressing, but Linux use 7-bit
|
||||
// addressing, so convert to 7-bit addressing format.
|
||||
//
|
||||
address = address >> 1;
|
||||
|
||||
//
|
||||
// Check if its valid port
|
||||
//
|
||||
if (!(linuxI2CSwPort >= 0 && linuxI2CSwPort < MAX_TEGRA_I2C_PORTS))
|
||||
{
|
||||
nv_printf(NV_DBG_ERRORS, "Invalid I2C port:%d\n", linuxI2CSwPort);
|
||||
return NV_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
for (count = 0; count < num_msgs; count++) {
|
||||
//
|
||||
// RM style client address is 8-bit addressing, but Linux use 7-bit
|
||||
// addressing, so convert to 7-bit addressing format.
|
||||
//
|
||||
nv_msgs[count].addr = nv_msgs[count].addr >> 1;
|
||||
|
||||
client = nv_i2c_get_registered_client(nv, linuxI2CSwPort, nv_msgs[count].addr);
|
||||
if (client == NULL)
|
||||
{
|
||||
client = nv_i2c_register_client(nv, linuxI2CSwPort, nv_msgs[count].addr);
|
||||
if (client == NULL)
|
||||
{
|
||||
nv_printf(NV_DBG_ERRORS, "i2c client register failed for addr:0x%x\n",
|
||||
nv_msgs[count].addr);
|
||||
return NV_ERR_GENERIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msgs = kzalloc((num_msgs * sizeof(*msgs)), GFP_KERNEL);
|
||||
if (msgs == NULL)
|
||||
{
|
||||
nv_printf(NV_DBG_ERRORS, "i2c message allocation failed\n");
|
||||
return NV_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (count = 0; count < num_msgs; count++) {
|
||||
msgs[count].addr = nv_msgs[count].addr;
|
||||
msgs[count].flags = nv_msgs[count].flags;
|
||||
msgs[count].len = nv_msgs[count].len;
|
||||
msgs[count].buf = nv_msgs[count].buf;
|
||||
}
|
||||
|
||||
rc = i2c_transfer(client->adapter, msgs, num_msgs);
|
||||
if (rc != num_msgs)
|
||||
{
|
||||
nv_printf(NV_DBG_ERRORS, "i2c transfer failed for addr:0x%x",
|
||||
address);
|
||||
status = NV_ERR_GENERIC;
|
||||
}
|
||||
|
||||
kfree(msgs);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void NV_API_CALL nv_i2c_unregister_clients(nv_state_t *nv)
|
||||
{
|
||||
nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
|
||||
int p_index, c_index;
|
||||
|
||||
for (p_index = 0; p_index < MAX_TEGRA_I2C_PORTS; p_index++)
|
||||
{
|
||||
for (c_index = 0;
|
||||
c_index < MAX_CLIENTS_PER_ADAPTER;
|
||||
c_index++)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
|
||||
client = (struct i2c_client *)nvl->i2c_clients[p_index].pOsClient[c_index];
|
||||
if (client)
|
||||
{
|
||||
#if defined(NV_I2C_UNREGISTER_DEVICE_PRESENT)
|
||||
i2c_unregister_device(client);
|
||||
#else
|
||||
nv_printf(NV_DBG_ERRORS, "i2c_unregister_device not present\n");
|
||||
#endif
|
||||
nvl->i2c_clients[p_index].pOsClient[c_index] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NV_STATUS NV_API_CALL nv_i2c_bus_status(
|
||||
nv_state_t *nv,
|
||||
NvU32 linuxI2CSwPort,
|
||||
NvS32 *scl,
|
||||
NvS32 *sda)
|
||||
{
|
||||
#if NV_IS_EXPORT_SYMBOL_PRESENT_i2c_bus_status
|
||||
nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
|
||||
struct i2c_adapter *i2c_adapter;
|
||||
int ret;
|
||||
|
||||
//
|
||||
// Check if its valid port
|
||||
//
|
||||
if (!(linuxI2CSwPort >= 0 && linuxI2CSwPort < MAX_TEGRA_I2C_PORTS))
|
||||
{
|
||||
nv_printf(NV_DBG_ERRORS, "Invalid I2C port:%d\n", linuxI2CSwPort);
|
||||
return NV_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/* Get the adapter using i2c port */
|
||||
i2c_adapter = i2c_get_adapter(linuxI2CSwPort);
|
||||
if (i2c_adapter == NULL)
|
||||
{
|
||||
nv_printf(NV_DBG_ERRORS, "Unable to get i2c adapter for port(%d)",
|
||||
linuxI2CSwPort);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ret = i2c_bus_status(i2c_adapter, scl, sda);
|
||||
if (ret < 0)
|
||||
{
|
||||
nv_printf(NV_DBG_ERRORS, "i2c_bus_status failed:%d\n", ret);
|
||||
return NV_ERR_GENERIC;
|
||||
}
|
||||
i2c_put_adapter(i2c_adapter);
|
||||
|
||||
return NV_OK;
|
||||
#else
|
||||
return NV_ERR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
#endif // NV_SUPPORTS_PLATFORM_DISPLAY_DEVICE
|
||||
#endif // defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
|
||||
#if !defined(CONFIG_I2C) && !defined(CONFIG_I2C_MODULE)
|
||||
|
||||
void NV_API_CALL nv_i2c_del_adapter(nv_state_t *nv, void *data)
|
||||
{
|
||||
@@ -296,5 +528,33 @@ void* NV_API_CALL nv_i2c_add_adapter(nv_state_t *nv, NvU32 port)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
|
||||
#if !NV_SUPPORTS_PLATFORM_DISPLAY_DEVICE
|
||||
|
||||
NV_STATUS NV_API_CALL nv_i2c_transfer(
|
||||
nv_state_t *nv,
|
||||
NvU32 linuxI2CSwPort,
|
||||
NvU8 address,
|
||||
nv_i2c_msg_t *nv_msgs,
|
||||
int num_msgs
|
||||
)
|
||||
{
|
||||
return NV_OK;
|
||||
}
|
||||
|
||||
void NV_API_CALL nv_i2c_unregister_clients(nv_state_t *nv)
|
||||
{
|
||||
}
|
||||
|
||||
NV_STATUS NV_API_CALL nv_i2c_bus_status(
|
||||
nv_state_t *nv,
|
||||
NvU32 linuxI2CSwPort,
|
||||
NvS32 *scl,
|
||||
NvS32 *sda)
|
||||
{
|
||||
return NV_ERR_GENERIC;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user