mirror of
https://github.com/apache/nuttx.git
synced 2025-01-13 09:49:21 +08:00
311 lines
8.7 KiB
C
311 lines
8.7 KiB
C
|
/****************************************************************************
|
||
|
* drivers/i3c/device.c
|
||
|
*
|
||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||
|
* contributor license agreements. See the NOTICE file distributed with
|
||
|
* this work for additional information regarding copyright ownership. The
|
||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||
|
* "License"); you may not use this file except in compliance with the
|
||
|
* License. You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||
|
* License for the specific language governing permissions and limitations
|
||
|
* under the License.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Included Files
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "internals.h"
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Public Functions
|
||
|
****************************************************************************/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: i3c_device_do_priv_xfers
|
||
|
*
|
||
|
* Description:
|
||
|
* Do I3C SDR private transfers directed to a specific device.
|
||
|
*
|
||
|
* Initiate one or several private SDR transfers with @dev.
|
||
|
*
|
||
|
* This function can sleep and thus cannot be called in atomic context.
|
||
|
*
|
||
|
* Input Parameters:
|
||
|
* dev - Device with which the transfers should be done
|
||
|
* xfers - Array of transfers
|
||
|
* nxfers - Number of transfers
|
||
|
*
|
||
|
* Returned Value:
|
||
|
* 0 in case of success, a negative error core otherwise.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
int i3c_device_do_priv_xfers(FAR const struct i3c_device *dev,
|
||
|
FAR struct i3c_priv_xfer *xfers,
|
||
|
int nxfers)
|
||
|
{
|
||
|
int ret;
|
||
|
int i;
|
||
|
|
||
|
if (nxfers < 1)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < nxfers; i++)
|
||
|
{
|
||
|
if (!xfers[i].len || !xfers[i].data.in)
|
||
|
{
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_lock(dev->bus);
|
||
|
ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
|
||
|
i3c_bus_normaluse_unlock(dev->bus);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: i3c_device_get_info
|
||
|
* Get I3C device information, Retrieve I3C dev info.
|
||
|
*
|
||
|
* Input Parameters:
|
||
|
* dev - Device we want information on.
|
||
|
* info - The information object to fill in.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
void i3c_device_get_info(FAR const struct i3c_device *dev,
|
||
|
FAR struct i3c_device_info *info)
|
||
|
{
|
||
|
if (!info)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_lock(dev->bus);
|
||
|
if (dev->desc)
|
||
|
{
|
||
|
*info = dev->desc->info;
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_unlock(dev->bus);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: i3c_device_disable_ibi
|
||
|
*
|
||
|
* Description:
|
||
|
* Disable IBIs coming from a specific device.
|
||
|
*
|
||
|
* This function disable IBIs coming from a specific device and wait for
|
||
|
* all pending IBIs to be processed.
|
||
|
*
|
||
|
* Input Parameters:
|
||
|
* dev - Device on which IBIs should be disabled
|
||
|
*
|
||
|
* Returned Value:
|
||
|
* 0 in case of success, a negative error core otherwise.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
int i3c_device_disable_ibi(FAR const struct i3c_device *dev)
|
||
|
{
|
||
|
int ret = -ENOENT;
|
||
|
|
||
|
i3c_bus_normaluse_lock(dev->bus);
|
||
|
if (dev->desc)
|
||
|
{
|
||
|
nxmutex_lock(&dev->desc->ibi_lock);
|
||
|
ret = i3c_dev_disable_ibi_locked(dev->desc);
|
||
|
nxmutex_unlock(&dev->desc->ibi_lock);
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_unlock(dev->bus);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: i3c_device_enable_ibi
|
||
|
*
|
||
|
* Description:
|
||
|
* Enable IBIs coming from a specific device.
|
||
|
*
|
||
|
* This function enable IBIs coming from a specific device and wait for
|
||
|
* all pending IBIs to be processed. This should be called on a device
|
||
|
* where i3c_device_request_ibi() has succeeded.
|
||
|
*
|
||
|
* Note that IBIs from this device might be received before this function
|
||
|
* returns to its caller.
|
||
|
*
|
||
|
* Input Parameters:
|
||
|
* dev - Device on which IBIs should be enabled
|
||
|
*
|
||
|
* Returned Value:
|
||
|
* 0 in case of success, a negative error core otherwise.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
int i3c_device_enable_ibi(FAR const struct i3c_device *dev)
|
||
|
{
|
||
|
int ret = -ENOENT;
|
||
|
|
||
|
i3c_bus_normaluse_lock(dev->bus);
|
||
|
if (dev->desc)
|
||
|
{
|
||
|
nxmutex_lock(&dev->desc->ibi_lock);
|
||
|
ret = i3c_dev_enable_ibi_locked(dev->desc);
|
||
|
nxmutex_unlock(&dev->desc->ibi_lock);
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_unlock(dev->bus);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: i3c_device_request_ibi
|
||
|
*
|
||
|
* Description:
|
||
|
* Request an IBI.
|
||
|
*
|
||
|
* This function is responsible for pre-allocating all resources needed to
|
||
|
* process IBIs coming from @dev. When this function returns, the IBI is
|
||
|
* not enabled until i3c_device_enable_ibi() is called.
|
||
|
*
|
||
|
* Input Parameters:
|
||
|
* dev - Device for which we should enable IBIs
|
||
|
* req - Setup requested for this IBI
|
||
|
*
|
||
|
* Returned Value:
|
||
|
* 0 in case of success, a negative error core otherwise.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
int i3c_device_request_ibi(FAR const struct i3c_device *dev,
|
||
|
FAR const struct i3c_ibi_setup *req)
|
||
|
{
|
||
|
int ret = -ENOENT;
|
||
|
|
||
|
if (!req->handler || !req->num_slots)
|
||
|
{
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_lock(dev->bus);
|
||
|
if (dev->desc)
|
||
|
{
|
||
|
nxmutex_lock(&dev->desc->ibi_lock);
|
||
|
ret = i3c_dev_request_ibi_locked(dev->desc, req);
|
||
|
nxmutex_unlock(&dev->desc->ibi_lock);
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_unlock(dev->bus);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: i3c_device_free_ibi
|
||
|
*
|
||
|
* Description:
|
||
|
* Free all resources needed for IBI handling.
|
||
|
*
|
||
|
* This function is responsible for de-allocating resources previously
|
||
|
* allocated by i3c_device_request_ibi(). It should be called after
|
||
|
* disabling IBIs with i3c_device_disable_ibi().
|
||
|
*
|
||
|
* Input Parameters:
|
||
|
* dev - Device on which you want to release IBI resources
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
void i3c_device_free_ibi(FAR const struct i3c_device *dev)
|
||
|
{
|
||
|
i3c_bus_normaluse_lock(dev->bus);
|
||
|
if (dev->desc)
|
||
|
{
|
||
|
nxmutex_lock(&dev->desc->ibi_lock);
|
||
|
i3c_dev_free_ibi_locked(dev->desc);
|
||
|
nxmutex_unlock(&dev->desc->ibi_lock);
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_unlock(dev->bus);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: i3c_master_find_i3c_dev
|
||
|
*
|
||
|
* Description:
|
||
|
* This function is used to be find a i3c_device address by master handle
|
||
|
* and provisional ID.
|
||
|
*
|
||
|
* Input Parameters:
|
||
|
* master - The master used to get i3c_device on the bus
|
||
|
* id - An instance of i3c_device_id, include manufid,partid and so on.
|
||
|
*
|
||
|
* Returned Value:
|
||
|
* Struct i3c_device var in case of success, NULL otherwise.
|
||
|
****************************************************************************/
|
||
|
|
||
|
FAR const struct i3c_device *i3c_master_find_i3c_dev(
|
||
|
FAR struct i3c_master_controller *master,
|
||
|
FAR const struct i3c_device_id *id)
|
||
|
{
|
||
|
FAR struct i3c_dev_desc *desc;
|
||
|
uint16_t manuf;
|
||
|
uint16_t part;
|
||
|
uint16_t ext_info;
|
||
|
bool rndpid;
|
||
|
|
||
|
i3c_bus_normaluse_lock(&master->bus);
|
||
|
i3c_bus_for_each_i3cdev(&master->bus, desc)
|
||
|
{
|
||
|
manuf = I3C_PID_MANUF_ID(desc->info.pid);
|
||
|
part = I3C_PID_PART_ID(desc->info.pid);
|
||
|
ext_info = I3C_PID_EXTRA_INFO(desc->info.pid);
|
||
|
rndpid = I3C_PID_RND_LOWER_32BITS(desc->info.pid);
|
||
|
|
||
|
if ((id->match_flags & I3C_MATCH_DCR) &&
|
||
|
id->dcr != desc->info.dcr)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ((id->match_flags & I3C_MATCH_MANUF) &&
|
||
|
id->manuf_id != manuf)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ((id->match_flags & I3C_MATCH_PART) &&
|
||
|
(rndpid || id->part_id != part))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
|
||
|
(rndpid || id->extra_info != ext_info))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_unlock(&master->bus);
|
||
|
return desc->dev;
|
||
|
}
|
||
|
|
||
|
i3c_bus_normaluse_unlock(&master->bus);
|
||
|
return NULL;
|
||
|
}
|