I3C for 7.1
Subsystem: - add sysfs option to rescan bus via entdaa - fix error code handling for send_ccc_cmd Drivers: - mipi-i3c-hci-pci: Intel Nova Lake-H I3C support -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmnkAa8ACgkQY6TcMGxw OjKwAhAAs1dbW2vzIaz6Y4zfyyhbVeMAkfx1yj/ekegTRQW/1MiR7k4C8GF0aQQR p3gbchFDrXdGzmGKwT7Y8Gcol4ml3hw4/6yrlHojRAVcfoIdKgYfF2+ffqDjl0Md FKRBjP8IzJ1i9GKA1PyDzw8YvWKbcl14Tb0PgctVTLcsTfPF8NHIJ3i04hBEA2vW Ro0NbRwBeBypXTAkldB0ZOXaS9qyOqoxZskFe1kmGCG05Rlo92kMCMRjjX5H0TVv laWMLEv34MsoIArTi77KZtJGYhDBckdrETFIiJf5xWVTyVyIH1PILIIgsy+nBO4L 0LsBnuhMyIA5AAUctIj63oZxLSIkTkNqk/Ii178dr/K6UfXtSt93q8Cgzdkh8Khy PLDVi8HBuLBmHqXmhtTatt8eerFuyJUUP3X3PnHXfJqTgHNfJN1yLYsLIX52S2h4 c1GxuacDruX5stCvRn0DGiXozKruS45ce1EhbUOMUtImbWbau0DBoujqCZRQpSCW LEZo+DMQ+GCNb8hqHW6seV/c4N8ul/R84INUBswaDFIJArsy8KPPIcgG+7l8fGC+ yHjbcxlR2gri7aaNjSjU36deNaOcSqcQoKJ97Ylhuba1HE2bCV4oV3ngI9k7hUbR aMxuN83r8ImiUvLKRh42IxjG6wAeVuYGVe6ohl3iK0uzgLL2Ux8= =7ohQ -----END PGP SIGNATURE----- Merge tag 'i3c/for-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux Pull i3c updates from Alexandre Belloni: "Subsystem: - add sysfs option to rescan bus via entdaa - fix error code handling for send_ccc_cmd Drivers: - mipi-i3c-hci-pci: Intel Nova Lake-H I3C support" * tag 'i3c/for-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: (22 commits) i3c: mipi-i3c-hci: fix IBI payload length calculation for final status i3c: master: adi: Fix error propagation for CCCs i3c: master: Fix error codes at send_ccc_cmd i3c: master: Move bus_init error suppression i3c: master: Move entdaa error suppression i3c: master: Move rstdaa error suppression i3c: dw: Simplify xfer cleanup with __free(kfree) i3c: dw: Fix memory leak in dw_i3c_master_i3c_xfers() i3c: master: renesas: Use __free(kfree) for xfer cleanup in renesas_i3c_send_ccc_cmd() i3c: master: renesas: Fix memory leak in renesas_i3c_i3c_xfers() i3c: master: dw-i3c: Balance PM runtime usage count on probe failure i3c: master: dw-i3c: Fix missing reset assertion in remove() callback i3c: mipi-i3c-hci-pci: Enable IBI while runtime suspended for Intel controllers i3c: mipi-i3c-hci-pci: Add optional ability to manage child runtime PM i3c: mipi-i3c-hci: Allow parent to manage runtime PM i3c: mipi-i3c-hci: Add quirk to allow IBI while runtime suspended i3c: mipi-i3c-hci-pci: Set d3hot_delay to 0 for Intel controllers i3c: fix missing newline in dev_err messages i3c: master: use kzalloc_flex i3c: mipi-i3c-hci-pci: Add support for Intel Nova Lake-H I3C ...master
commit
401b0e0bc9
|
|
@ -172,3 +172,23 @@ Description:
|
|||
the automatic retries. Exist only when I3C constroller supports
|
||||
this retry on nack feature.
|
||||
|
||||
What: /sys/bus/i3c/devices/i3c-<bus-id>/do_daa
|
||||
KernelVersion: 7.0
|
||||
Contact: linux-i3c@vger.kernel.org
|
||||
Description:
|
||||
Write-only attribute that triggers a Dynamic Address Assignment
|
||||
(DAA) procedure which discovers new I3C devices on the bus.
|
||||
Writing a boolean true value (1, y, yes, true, on) to this
|
||||
attribute causes the master controller to perform DAA, which
|
||||
includes broadcasting an ENTDAA (Enter Dynamic Address Assignment)
|
||||
Common Command Code (CCC) on the bus. Writing a false value
|
||||
returns -EINVAL.
|
||||
|
||||
This is useful for discovering I3C devices that were not present
|
||||
during initial bus initialization and are unable to issue
|
||||
Hot-Join. Only devices without a currently assigned dynamic address
|
||||
will respond to the ENTDAA broadcast and be assigned addresses.
|
||||
|
||||
Note that this mechanism is distinct from Hot-Join, since this is
|
||||
controller-initiated discovery, while Hot-Join is device-initiated
|
||||
method to provoke controller discovery procedure.
|
||||
|
|
|
|||
|
|
@ -758,6 +758,32 @@ static ssize_t dev_nack_retry_count_store(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR_RW(dev_nack_retry_count);
|
||||
|
||||
static ssize_t do_daa_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i3c_master_controller *master = dev_to_i3cmaster(dev);
|
||||
bool val;
|
||||
int ret;
|
||||
|
||||
if (kstrtobool(buf, &val))
|
||||
return -EINVAL;
|
||||
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
if (!master->init_done)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = i3c_master_do_daa(master);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_WO(do_daa);
|
||||
|
||||
static struct attribute *i3c_masterdev_attrs[] = {
|
||||
&dev_attr_mode.attr,
|
||||
&dev_attr_current_master.attr,
|
||||
|
|
@ -769,6 +795,7 @@ static struct attribute *i3c_masterdev_attrs[] = {
|
|||
&dev_attr_dynamic_address.attr,
|
||||
&dev_attr_hdrcap.attr,
|
||||
&dev_attr_hotjoin.attr,
|
||||
&dev_attr_do_daa.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(i3c_masterdev);
|
||||
|
|
@ -898,11 +925,17 @@ static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id,
|
|||
cmd->err = I3C_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* i3c_master_send_ccc_cmd_locked() - send a CCC (Common Command Codes)
|
||||
* @master: master used to send frames on the bus
|
||||
* @cmd: command to send
|
||||
*
|
||||
* Return: 0 in case of success, or a negative error code otherwise.
|
||||
* I3C Mx error codes are stored in cmd->err.
|
||||
*/
|
||||
static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master,
|
||||
struct i3c_ccc_cmd *cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!cmd || !master)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -920,15 +953,7 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master,
|
|||
!master->ops->supports_ccc_cmd(master, cmd))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = master->ops->send_ccc_cmd(master, cmd);
|
||||
if (ret) {
|
||||
if (cmd->err != I3C_ERROR_UNKNOWN)
|
||||
return cmd->err;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return master->ops->send_ccc_cmd(master, cmd);
|
||||
}
|
||||
|
||||
static struct i2c_dev_desc *
|
||||
|
|
@ -1016,6 +1041,10 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master,
|
|||
ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
|
||||
i3c_ccc_cmd_dest_cleanup(&dest);
|
||||
|
||||
/* No active devices on the bus. */
|
||||
if (ret && cmd.err == I3C_ERROR_M2)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1032,8 +1061,7 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master,
|
|||
*
|
||||
* This function must be called with the bus lock held in write mode.
|
||||
*
|
||||
* Return: 0 in case of success, a positive I3C error code if the error is
|
||||
* one of the official Mx error codes, and a negative error code otherwise.
|
||||
* Return: 0 in case of success, or a negative error code otherwise.
|
||||
*/
|
||||
int i3c_master_entdaa_locked(struct i3c_master_controller *master)
|
||||
{
|
||||
|
|
@ -1046,12 +1074,17 @@ int i3c_master_entdaa_locked(struct i3c_master_controller *master)
|
|||
ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
|
||||
i3c_ccc_cmd_dest_cleanup(&dest);
|
||||
|
||||
/* No active devices need an address. */
|
||||
if (ret && cmd.err == I3C_ERROR_M2)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_master_entdaa_locked);
|
||||
|
||||
static int i3c_master_enec_disec_locked(struct i3c_master_controller *master,
|
||||
u8 addr, bool enable, u8 evts)
|
||||
u8 addr, bool enable, u8 evts,
|
||||
bool suppress_m2)
|
||||
{
|
||||
struct i3c_ccc_events *events;
|
||||
struct i3c_ccc_cmd_dest dest;
|
||||
|
|
@ -1071,6 +1104,9 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master,
|
|||
ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
|
||||
i3c_ccc_cmd_dest_cleanup(&dest);
|
||||
|
||||
if (suppress_m2 && ret && cmd.err == I3C_ERROR_M2)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1085,13 +1121,12 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master,
|
|||
*
|
||||
* This function must be called with the bus lock held in write mode.
|
||||
*
|
||||
* Return: 0 in case of success, a positive I3C error code if the error is
|
||||
* one of the official Mx error codes, and a negative error code otherwise.
|
||||
* Return: 0 in case of success, or a negative error code otherwise.
|
||||
*/
|
||||
int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr,
|
||||
u8 evts)
|
||||
{
|
||||
return i3c_master_enec_disec_locked(master, addr, false, evts);
|
||||
return i3c_master_enec_disec_locked(master, addr, false, evts, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_master_disec_locked);
|
||||
|
||||
|
|
@ -1106,13 +1141,12 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked);
|
|||
*
|
||||
* This function must be called with the bus lock held in write mode.
|
||||
*
|
||||
* Return: 0 in case of success, a positive I3C error code if the error is
|
||||
* one of the official Mx error codes, and a negative error code otherwise.
|
||||
* Return: 0 in case of success, or a negative error code otherwise.
|
||||
*/
|
||||
int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr,
|
||||
u8 evts)
|
||||
{
|
||||
return i3c_master_enec_disec_locked(master, addr, true, evts);
|
||||
return i3c_master_enec_disec_locked(master, addr, true, evts, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_master_enec_locked);
|
||||
|
||||
|
|
@ -1132,8 +1166,7 @@ EXPORT_SYMBOL_GPL(i3c_master_enec_locked);
|
|||
*
|
||||
* This function must be called with the bus lock held in write mode.
|
||||
*
|
||||
* Return: 0 in case of success, a positive I3C error code if the error is
|
||||
* one of the official Mx error codes, and a negative error code otherwise.
|
||||
* Return: 0 in case of success, or a negative error code otherwise.
|
||||
*/
|
||||
int i3c_master_defslvs_locked(struct i3c_master_controller *master)
|
||||
{
|
||||
|
|
@ -1794,11 +1827,8 @@ int i3c_master_do_daa_ext(struct i3c_master_controller *master, bool rstdaa)
|
|||
|
||||
i3c_bus_maintenance_lock(&master->bus);
|
||||
|
||||
if (rstdaa) {
|
||||
if (rstdaa)
|
||||
rstret = i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR);
|
||||
if (rstret == I3C_ERROR_M2)
|
||||
rstret = 0;
|
||||
}
|
||||
|
||||
ret = master->ops->do_daa(master);
|
||||
|
||||
|
|
@ -2093,7 +2123,7 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
|
|||
* (assigned by the bootloader for example).
|
||||
*/
|
||||
ret = i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR);
|
||||
if (ret && ret != I3C_ERROR_M2)
|
||||
if (ret)
|
||||
goto err_bus_cleanup;
|
||||
|
||||
if (master->ops->set_speed) {
|
||||
|
|
@ -2102,11 +2132,14 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
|
|||
goto err_bus_cleanup;
|
||||
}
|
||||
|
||||
/* Disable all slave events before starting DAA. */
|
||||
ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR,
|
||||
I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR |
|
||||
I3C_CCC_EVENT_HJ);
|
||||
if (ret && ret != I3C_ERROR_M2)
|
||||
/*
|
||||
* Disable all slave events before starting DAA. When no active device
|
||||
* is on the bus, returns Mx error code M2, this error is ignored.
|
||||
*/
|
||||
ret = i3c_master_enec_disec_locked(master, I3C_BROADCAST_ADDR, false,
|
||||
I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR |
|
||||
I3C_CCC_EVENT_HJ, true);
|
||||
if (ret)
|
||||
goto err_bus_cleanup;
|
||||
|
||||
/*
|
||||
|
|
@ -2396,7 +2429,7 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
|
|||
* DEFSLVS command.
|
||||
*/
|
||||
if (boardinfo->base.flags & I2C_CLIENT_TEN) {
|
||||
dev_err(dev, "I2C device with 10 bit address not supported.");
|
||||
dev_err(dev, "I2C device with 10 bit address not supported.\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
|
@ -2793,10 +2826,10 @@ struct i3c_generic_ibi_slot {
|
|||
struct i3c_generic_ibi_pool {
|
||||
spinlock_t lock;
|
||||
unsigned int num_slots;
|
||||
struct i3c_generic_ibi_slot *slots;
|
||||
void *payload_buf;
|
||||
struct list_head free_slots;
|
||||
struct list_head pending;
|
||||
struct i3c_generic_ibi_slot slots[] __counted_by(num_slots);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2824,7 +2857,6 @@ void i3c_generic_ibi_free_pool(struct i3c_generic_ibi_pool *pool)
|
|||
WARN_ON(nslots != pool->num_slots);
|
||||
|
||||
kfree(pool->payload_buf);
|
||||
kfree(pool->slots);
|
||||
kfree(pool);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_generic_ibi_free_pool);
|
||||
|
|
@ -2847,20 +2879,16 @@ i3c_generic_ibi_alloc_pool(struct i3c_dev_desc *dev,
|
|||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
pool = kzalloc_obj(*pool);
|
||||
pool = kzalloc_flex(*pool, slots, req->num_slots);
|
||||
if (!pool)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pool->num_slots = req->num_slots;
|
||||
|
||||
spin_lock_init(&pool->lock);
|
||||
INIT_LIST_HEAD(&pool->free_slots);
|
||||
INIT_LIST_HEAD(&pool->pending);
|
||||
|
||||
pool->slots = kzalloc_objs(*slot, req->num_slots);
|
||||
if (!pool->slots) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_pool;
|
||||
}
|
||||
|
||||
if (req->max_payload_len) {
|
||||
pool->payload_buf = kcalloc(req->num_slots,
|
||||
req->max_payload_len, GFP_KERNEL);
|
||||
|
|
@ -2879,7 +2907,6 @@ i3c_generic_ibi_alloc_pool(struct i3c_dev_desc *dev,
|
|||
(i * req->max_payload_len);
|
||||
|
||||
list_add_tail(&slot->node, &pool->free_slots);
|
||||
pool->num_slots++;
|
||||
}
|
||||
|
||||
return pool;
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
|
|||
|
||||
cmd->err = adi_i3c_cmd_get_err(&xfer->cmds[0]);
|
||||
|
||||
return 0;
|
||||
return xfer->ret;
|
||||
}
|
||||
|
||||
static int adi_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
|
||||
|
|
@ -655,8 +655,7 @@ static int adi_i3c_master_do_daa(struct i3c_master_controller *m)
|
|||
|
||||
writel(irq_mask, master->regs + REG_IRQ_MASK);
|
||||
|
||||
/* DAA always finishes with CE2_ERROR or NACK_RESP */
|
||||
if (ret && ret != I3C_ERROR_M2)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Add I3C devices discovered */
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/err.h>
|
||||
|
|
@ -393,11 +394,6 @@ dw_i3c_master_alloc_xfer(struct dw_i3c_master *master, unsigned int ncmds)
|
|||
return xfer;
|
||||
}
|
||||
|
||||
static void dw_i3c_master_free_xfer(struct dw_i3c_xfer *xfer)
|
||||
{
|
||||
kfree(xfer);
|
||||
}
|
||||
|
||||
static void dw_i3c_master_start_xfer_locked(struct dw_i3c_master *master)
|
||||
{
|
||||
struct dw_i3c_xfer *xfer = master->xferqueue.cur;
|
||||
|
|
@ -715,7 +711,6 @@ static void dw_i3c_master_bus_cleanup(struct i3c_master_controller *m)
|
|||
static int dw_i3c_ccc_set(struct dw_i3c_master *master,
|
||||
struct i3c_ccc_cmd *ccc)
|
||||
{
|
||||
struct dw_i3c_xfer *xfer;
|
||||
struct dw_i3c_cmd *cmd;
|
||||
int ret, pos = 0;
|
||||
|
||||
|
|
@ -725,7 +720,7 @@ static int dw_i3c_ccc_set(struct dw_i3c_master *master,
|
|||
return pos;
|
||||
}
|
||||
|
||||
xfer = dw_i3c_master_alloc_xfer(master, 1);
|
||||
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, 1);
|
||||
if (!xfer)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -750,14 +745,11 @@ static int dw_i3c_ccc_set(struct dw_i3c_master *master,
|
|||
if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK)
|
||||
ccc->err = I3C_ERROR_M2;
|
||||
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc)
|
||||
{
|
||||
struct dw_i3c_xfer *xfer;
|
||||
struct dw_i3c_cmd *cmd;
|
||||
int ret, pos;
|
||||
|
||||
|
|
@ -765,7 +757,7 @@ static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc)
|
|||
if (pos < 0)
|
||||
return pos;
|
||||
|
||||
xfer = dw_i3c_master_alloc_xfer(master, 1);
|
||||
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, 1);
|
||||
if (!xfer)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -790,7 +782,6 @@ static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc)
|
|||
ret = xfer->ret;
|
||||
if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK)
|
||||
ccc->err = I3C_ERROR_M2;
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -837,12 +828,15 @@ static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
|
|||
static int dw_i3c_master_daa(struct i3c_master_controller *m)
|
||||
{
|
||||
struct dw_i3c_master *master = to_dw_i3c_master(m);
|
||||
struct dw_i3c_xfer *xfer;
|
||||
struct dw_i3c_cmd *cmd;
|
||||
u32 olddevs, newdevs;
|
||||
u8 last_addr = 0;
|
||||
int ret, pos;
|
||||
|
||||
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, 1);
|
||||
if (!xfer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = pm_runtime_resume_and_get(master->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(master->dev,
|
||||
|
|
@ -876,15 +870,8 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
|
|||
ret = 0;
|
||||
}
|
||||
|
||||
xfer = dw_i3c_master_alloc_xfer(master, 1);
|
||||
if (!xfer) {
|
||||
ret = -ENOMEM;
|
||||
goto rpm_out;
|
||||
}
|
||||
|
||||
pos = dw_i3c_master_get_free_pos(master);
|
||||
if (pos < 0) {
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
ret = pos;
|
||||
goto rpm_out;
|
||||
}
|
||||
|
|
@ -909,8 +896,6 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
|
|||
i3c_master_add_i3c_dev_locked(m, master->devs[pos].addr);
|
||||
}
|
||||
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
|
||||
rpm_out:
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return ret;
|
||||
|
|
@ -924,7 +909,6 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
|
|||
struct i3c_master_controller *m = i3c_dev_get_master(dev);
|
||||
struct dw_i3c_master *master = to_dw_i3c_master(m);
|
||||
unsigned int nrxwords = 0, ntxwords = 0;
|
||||
struct dw_i3c_xfer *xfer;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!i3c_nxfers)
|
||||
|
|
@ -944,7 +928,7 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
|
|||
nrxwords > master->caps.datafifodepth)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
|
||||
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
|
||||
if (!xfer)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -995,7 +979,6 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
|
|||
}
|
||||
|
||||
ret = xfer->ret;
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return ret;
|
||||
|
|
@ -1084,7 +1067,6 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
|||
struct i3c_master_controller *m = i2c_dev_get_master(dev);
|
||||
struct dw_i3c_master *master = to_dw_i3c_master(m);
|
||||
unsigned int nrxwords = 0, ntxwords = 0;
|
||||
struct dw_i3c_xfer *xfer;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!i2c_nxfers)
|
||||
|
|
@ -1104,7 +1086,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
|||
nrxwords > master->caps.datafifodepth)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers);
|
||||
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, i2c_nxfers);
|
||||
if (!xfer)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -1113,7 +1095,6 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
|||
dev_err(master->dev,
|
||||
"<%s> cannot resume i3c bus master, err: %d\n",
|
||||
__func__, ret);
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1145,7 +1126,6 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
|||
dw_i3c_master_dequeue_xfer(master, xfer);
|
||||
|
||||
ret = xfer->ret;
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return ret;
|
||||
|
|
@ -1606,13 +1586,11 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
|
|||
if (IS_ERR(master->pclk))
|
||||
return PTR_ERR(master->pclk);
|
||||
|
||||
master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
|
||||
"core_rst");
|
||||
master->core_rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev,
|
||||
"core_rst");
|
||||
if (IS_ERR(master->core_rst))
|
||||
return PTR_ERR(master->core_rst);
|
||||
|
||||
reset_control_deassert(master->core_rst);
|
||||
|
||||
spin_lock_init(&master->xferqueue.lock);
|
||||
INIT_LIST_HEAD(&master->xferqueue.list);
|
||||
|
||||
|
|
@ -1624,7 +1602,7 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
|
|||
dw_i3c_master_irq_handler, 0,
|
||||
dev_name(&pdev->dev), master);
|
||||
if (ret)
|
||||
goto err_assert_rst;
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, master);
|
||||
|
||||
|
|
@ -1669,13 +1647,12 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
|
|||
return 0;
|
||||
|
||||
err_disable_pm:
|
||||
if (master->quirks & DW_I3C_DISABLE_RUNTIME_PM_QUIRK)
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
|
||||
err_assert_rst:
|
||||
reset_control_assert(master->core_rst);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_i3c_common_probe);
|
||||
|
|
|
|||
|
|
@ -1143,7 +1143,7 @@ static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
|
|||
}
|
||||
|
||||
ret = i3c_master_entdaa_locked(&master->base);
|
||||
if (ret && ret != I3C_ERROR_M2)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
newdevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
|
||||
|
|
|
|||
|
|
@ -759,7 +759,7 @@ static int i3c_hci_reset_and_init(struct i3c_hci *hci)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int i3c_hci_runtime_suspend(struct device *dev)
|
||||
int i3c_hci_rpm_suspend(struct device *dev)
|
||||
{
|
||||
struct i3c_hci *hci = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
|
@ -776,8 +776,9 @@ static int i3c_hci_runtime_suspend(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_hci_rpm_suspend);
|
||||
|
||||
static int i3c_hci_runtime_resume(struct device *dev)
|
||||
int i3c_hci_rpm_resume(struct device *dev)
|
||||
{
|
||||
struct i3c_hci *hci = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
|
@ -800,6 +801,27 @@ static int i3c_hci_runtime_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_hci_rpm_resume);
|
||||
|
||||
static int i3c_hci_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct i3c_hci *hci = dev_get_drvdata(dev);
|
||||
|
||||
if (hci->quirks & HCI_QUIRK_RPM_PARENT_MANAGED)
|
||||
return 0;
|
||||
|
||||
return i3c_hci_rpm_suspend(dev);
|
||||
}
|
||||
|
||||
static int i3c_hci_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct i3c_hci *hci = dev_get_drvdata(dev);
|
||||
|
||||
if (hci->quirks & HCI_QUIRK_RPM_PARENT_MANAGED)
|
||||
return 0;
|
||||
|
||||
return i3c_hci_rpm_resume(dev);
|
||||
}
|
||||
|
||||
static int i3c_hci_suspend(struct device *dev)
|
||||
{
|
||||
|
|
@ -844,8 +866,6 @@ static int i3c_hci_restore(struct device *dev)
|
|||
return i3c_hci_resume_common(dev, true);
|
||||
}
|
||||
|
||||
#define DEFAULT_AUTOSUSPEND_DELAY_MS 1000
|
||||
|
||||
static void i3c_hci_rpm_enable(struct device *dev)
|
||||
{
|
||||
struct i3c_hci *hci = dev_get_drvdata(dev);
|
||||
|
|
@ -996,6 +1016,9 @@ static int i3c_hci_probe(struct platform_device *pdev)
|
|||
if (hci->quirks & HCI_QUIRK_RPM_ALLOWED)
|
||||
i3c_hci_rpm_enable(&pdev->dev);
|
||||
|
||||
if (hci->quirks & HCI_QUIRK_RPM_IBI_ALLOWED)
|
||||
hci->master.rpm_ibi_allowed = true;
|
||||
|
||||
return i3c_master_register(&hci->master, &pdev->dev, &i3c_hci_ops, false);
|
||||
}
|
||||
|
||||
|
|
@ -1019,7 +1042,9 @@ static const struct acpi_device_id i3c_hci_acpi_match[] = {
|
|||
MODULE_DEVICE_TABLE(acpi, i3c_hci_acpi_match);
|
||||
|
||||
static const struct platform_device_id i3c_hci_driver_ids[] = {
|
||||
{ .name = "intel-lpss-i3c", HCI_QUIRK_RPM_ALLOWED },
|
||||
{ .name = "intel-lpss-i3c", HCI_QUIRK_RPM_ALLOWED |
|
||||
HCI_QUIRK_RPM_IBI_ALLOWED |
|
||||
HCI_QUIRK_RPM_PARENT_MANAGED },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, i3c_hci_driver_ids);
|
||||
|
|
|
|||
|
|
@ -754,7 +754,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
|
|||
if (!(ibi_status & IBI_LAST_STATUS)) {
|
||||
ibi_size += chunks * rh->ibi_chunk_sz;
|
||||
} else {
|
||||
ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status);
|
||||
if (chunks) {
|
||||
ibi_size += (chunks - 1) * rh->ibi_chunk_sz;
|
||||
ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status);
|
||||
}
|
||||
last_ptr = ptr;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ struct i3c_hci_dev_data {
|
|||
#define HCI_QUIRK_OD_PP_TIMING BIT(3) /* Set OD and PP timings for AMD platforms */
|
||||
#define HCI_QUIRK_RESP_BUF_THLD BIT(4) /* Set resp buf thld to 0 for AMD platforms */
|
||||
#define HCI_QUIRK_RPM_ALLOWED BIT(5) /* Runtime PM allowed */
|
||||
#define HCI_QUIRK_RPM_IBI_ALLOWED BIT(6) /* IBI and Hot-Join allowed while runtime suspended */
|
||||
#define HCI_QUIRK_RPM_PARENT_MANAGED BIT(7) /* Runtime PM managed by parent device */
|
||||
|
||||
/* global functions */
|
||||
void mipi_i3c_hci_resume(struct i3c_hci *hci);
|
||||
|
|
@ -160,4 +162,9 @@ void amd_set_resp_buf_thld(struct i3c_hci *hci);
|
|||
void i3c_hci_sync_irq_inactive(struct i3c_hci *hci);
|
||||
int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
|
||||
|
||||
#define DEFAULT_AUTOSUSPEND_DELAY_MS 1000
|
||||
|
||||
int i3c_hci_rpm_suspend(struct device *dev);
|
||||
int i3c_hci_rpm_resume(struct device *dev);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/i3c/master.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -20,16 +21,24 @@
|
|||
#include <linux/pm_qos.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "hci.h"
|
||||
|
||||
/*
|
||||
* There can up to 15 instances, but implementations have at most 2 at this
|
||||
* time.
|
||||
*/
|
||||
#define INST_MAX 2
|
||||
|
||||
struct mipi_i3c_hci_pci_instance {
|
||||
struct device *dev;
|
||||
bool operational;
|
||||
};
|
||||
|
||||
struct mipi_i3c_hci_pci {
|
||||
struct pci_dev *pci;
|
||||
void __iomem *base;
|
||||
const struct mipi_i3c_hci_pci_info *info;
|
||||
struct mipi_i3c_hci_pci_instance instance[INST_MAX];
|
||||
void *private;
|
||||
};
|
||||
|
||||
|
|
@ -40,6 +49,7 @@ struct mipi_i3c_hci_pci_info {
|
|||
int id[INST_MAX];
|
||||
u32 instance_offset[INST_MAX];
|
||||
int instance_count;
|
||||
bool control_instance_pm;
|
||||
};
|
||||
|
||||
#define INTEL_PRIV_OFFSET 0x2b0
|
||||
|
|
@ -164,6 +174,7 @@ static int intel_i3c_init(struct mipi_i3c_hci_pci *hci)
|
|||
dma_set_mask_and_coherent(&hci->pci->dev, DMA_BIT_MASK(64));
|
||||
|
||||
hci->pci->d3cold_delay = 0;
|
||||
hci->pci->d3hot_delay = 0;
|
||||
|
||||
hci->private = host;
|
||||
host->priv = priv;
|
||||
|
|
@ -189,6 +200,7 @@ static const struct mipi_i3c_hci_pci_info intel_mi_1_info = {
|
|||
.id = {0, 1},
|
||||
.instance_offset = {0, 0x400},
|
||||
.instance_count = 2,
|
||||
.control_instance_pm = true,
|
||||
};
|
||||
|
||||
static const struct mipi_i3c_hci_pci_info intel_mi_2_info = {
|
||||
|
|
@ -198,6 +210,7 @@ static const struct mipi_i3c_hci_pci_info intel_mi_2_info = {
|
|||
.id = {2, 3},
|
||||
.instance_offset = {0, 0x400},
|
||||
.instance_count = 2,
|
||||
.control_instance_pm = true,
|
||||
};
|
||||
|
||||
static const struct mipi_i3c_hci_pci_info intel_si_2_info = {
|
||||
|
|
@ -207,8 +220,128 @@ static const struct mipi_i3c_hci_pci_info intel_si_2_info = {
|
|||
.id = {2},
|
||||
.instance_offset = {0},
|
||||
.instance_count = 1,
|
||||
.control_instance_pm = true,
|
||||
};
|
||||
|
||||
static int mipi_i3c_hci_pci_find_instance(struct mipi_i3c_hci_pci *hci, struct device *dev)
|
||||
{
|
||||
for (int i = 0; i < INST_MAX; i++) {
|
||||
if (!hci->instance[i].dev)
|
||||
hci->instance[i].dev = dev;
|
||||
if (hci->instance[i].dev == dev)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define HC_CONTROL 0x04
|
||||
#define HC_CONTROL_BUS_ENABLE BIT(31)
|
||||
|
||||
static bool __mipi_i3c_hci_pci_is_operational(struct device *dev)
|
||||
{
|
||||
const struct mipi_i3c_hci_platform_data *pdata = dev->platform_data;
|
||||
u32 hc_control = readl(pdata->base_regs + HC_CONTROL);
|
||||
|
||||
return hc_control & HC_CONTROL_BUS_ENABLE;
|
||||
}
|
||||
|
||||
static bool mipi_i3c_hci_pci_is_operational(struct device *dev, bool update)
|
||||
{
|
||||
struct mipi_i3c_hci_pci *hci = dev_get_drvdata(dev->parent);
|
||||
int pos = mipi_i3c_hci_pci_find_instance(hci, dev);
|
||||
|
||||
if (pos < 0) {
|
||||
dev_err(dev, "%s: I3C instance not found\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (update)
|
||||
hci->instance[pos].operational = __mipi_i3c_hci_pci_is_operational(dev);
|
||||
|
||||
return hci->instance[pos].operational;
|
||||
}
|
||||
|
||||
struct mipi_i3c_hci_pci_pm_data {
|
||||
struct device *dev[INST_MAX];
|
||||
int dev_cnt;
|
||||
};
|
||||
|
||||
static bool mipi_i3c_hci_pci_is_mfd(struct device *dev)
|
||||
{
|
||||
return dev_is_platform(dev) && mfd_get_cell(to_platform_device(dev));
|
||||
}
|
||||
|
||||
static int mipi_i3c_hci_pci_suspend_instance(struct device *dev, void *data)
|
||||
{
|
||||
struct mipi_i3c_hci_pci_pm_data *pm_data = data;
|
||||
int ret;
|
||||
|
||||
if (!mipi_i3c_hci_pci_is_mfd(dev) ||
|
||||
!mipi_i3c_hci_pci_is_operational(dev, true))
|
||||
return 0;
|
||||
|
||||
ret = i3c_hci_rpm_suspend(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_data->dev[pm_data->dev_cnt++] = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mipi_i3c_hci_pci_resume_instance(struct device *dev, void *data)
|
||||
{
|
||||
struct mipi_i3c_hci_pci_pm_data *pm_data = data;
|
||||
int ret;
|
||||
|
||||
if (!mipi_i3c_hci_pci_is_mfd(dev) ||
|
||||
!mipi_i3c_hci_pci_is_operational(dev, false))
|
||||
return 0;
|
||||
|
||||
ret = i3c_hci_rpm_resume(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_data->dev[pm_data->dev_cnt++] = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mipi_i3c_hci_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct mipi_i3c_hci_pci *hci = dev_get_drvdata(dev);
|
||||
struct mipi_i3c_hci_pci_pm_data pm_data = {};
|
||||
int ret;
|
||||
|
||||
if (!hci->info->control_instance_pm)
|
||||
return 0;
|
||||
|
||||
ret = device_for_each_child_reverse(dev, &pm_data, mipi_i3c_hci_pci_suspend_instance);
|
||||
if (ret)
|
||||
for (int i = 0; i < pm_data.dev_cnt; i++)
|
||||
i3c_hci_rpm_resume(pm_data.dev[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mipi_i3c_hci_pci_resume(struct device *dev)
|
||||
{
|
||||
struct mipi_i3c_hci_pci *hci = dev_get_drvdata(dev);
|
||||
struct mipi_i3c_hci_pci_pm_data pm_data = {};
|
||||
int ret;
|
||||
|
||||
if (!hci->info->control_instance_pm)
|
||||
return 0;
|
||||
|
||||
ret = device_for_each_child(dev, &pm_data, mipi_i3c_hci_pci_resume_instance);
|
||||
if (ret)
|
||||
for (int i = 0; i < pm_data.dev_cnt; i++)
|
||||
i3c_hci_rpm_suspend(pm_data.dev[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mipi_i3c_hci_pci_rpm_allow(struct device *dev)
|
||||
{
|
||||
pm_runtime_put(dev);
|
||||
|
|
@ -322,6 +455,8 @@ static void mipi_i3c_hci_pci_remove(struct pci_dev *pci)
|
|||
|
||||
/* PM ops must exist for PCI to put a device to a low power state */
|
||||
static const struct dev_pm_ops mipi_i3c_hci_pci_pm_ops = {
|
||||
RUNTIME_PM_OPS(mipi_i3c_hci_pci_suspend, mipi_i3c_hci_pci_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(mipi_i3c_hci_pci_suspend, mipi_i3c_hci_pci_resume)
|
||||
};
|
||||
|
||||
static const struct pci_device_id mipi_i3c_hci_pci_devices[] = {
|
||||
|
|
@ -337,6 +472,9 @@ static const struct pci_device_id mipi_i3c_hci_pci_devices[] = {
|
|||
/* Nova Lake-S */
|
||||
{ PCI_VDEVICE(INTEL, 0x6e2c), (kernel_ulong_t)&intel_mi_1_info},
|
||||
{ PCI_VDEVICE(INTEL, 0x6e2d), (kernel_ulong_t)&intel_mi_2_info},
|
||||
/* Nova Lake-H */
|
||||
{ PCI_VDEVICE(INTEL, 0xd37c), (kernel_ulong_t)&intel_mi_1_info},
|
||||
{ PCI_VDEVICE(INTEL, 0xd36f), (kernel_ulong_t)&intel_mi_2_info},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, mipi_i3c_hci_pci_devices);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/err.h>
|
||||
|
|
@ -747,7 +748,6 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
|
|||
struct i3c_ccc_cmd *ccc)
|
||||
{
|
||||
struct renesas_i3c *i3c = to_renesas_i3c(m);
|
||||
struct renesas_i3c_xfer *xfer;
|
||||
struct renesas_i3c_cmd *cmd;
|
||||
int ret, pos = 0;
|
||||
|
||||
|
|
@ -757,7 +757,7 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
|
|||
return pos;
|
||||
}
|
||||
|
||||
xfer = renesas_i3c_alloc_xfer(i3c, 1);
|
||||
struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
|
||||
if (!xfer)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -806,8 +806,6 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
|
|||
if (ret)
|
||||
ccc->err = I3C_ERROR_M2;
|
||||
|
||||
kfree(xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -817,13 +815,12 @@ static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_
|
|||
struct i3c_master_controller *m = i3c_dev_get_master(dev);
|
||||
struct renesas_i3c *i3c = to_renesas_i3c(m);
|
||||
struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
|
||||
struct renesas_i3c_xfer *xfer;
|
||||
int i;
|
||||
|
||||
/* Enable I3C bus. */
|
||||
renesas_i3c_bus_enable(m, true);
|
||||
|
||||
xfer = renesas_i3c_alloc_xfer(i3c, 1);
|
||||
struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
|
||||
if (!xfer)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ static void svc_i3c_master_reset_fifo_trigger(struct svc_i3c_master *master)
|
|||
{
|
||||
u32 reg;
|
||||
|
||||
/* Set RX and TX tigger levels, flush FIFOs */
|
||||
/* Set RX and TX trigger levels, flush FIFOs */
|
||||
reg = SVC_I3C_MDATACTRL_FLUSHTB |
|
||||
SVC_I3C_MDATACTRL_FLUSHRB |
|
||||
SVC_I3C_MDATACTRL_UNLOCK_TRIG |
|
||||
|
|
@ -572,7 +572,7 @@ static void svc_i3c_master_ibi_isr(struct svc_i3c_master *master)
|
|||
* 3. IBI isr writes an AutoIBI request.
|
||||
* 4. The controller will not start AutoIBI process because SDA is not low.
|
||||
* 5. IBIWON polling times out.
|
||||
* 6. Controller reamins in AutoIBI state and doesn't accept EmitStop request.
|
||||
* 6. Controller remains in AutoIBI state and doesn't accept EmitStop request.
|
||||
*/
|
||||
writel(SVC_I3C_MCTRL_REQUEST_START_ADDR |
|
||||
SVC_I3C_MCTRL_TYPE_I3C |
|
||||
|
|
@ -774,7 +774,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
|
|||
|
||||
/*
|
||||
* Using I3C Open-Drain mode, target is 4.17MHz/240ns with a
|
||||
* duty-cycle tuned so that high levels are filetered out by
|
||||
* duty-cycle tuned so that high levels are filtered out by
|
||||
* the 50ns filter (target being 40ns).
|
||||
*/
|
||||
odhpp = 1;
|
||||
|
|
@ -1268,7 +1268,7 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
|
|||
/* Configure IBI auto-rules */
|
||||
ret = svc_i3c_update_ibirules(master);
|
||||
if (ret)
|
||||
dev_err(master->dev, "Cannot handle such a list of devices");
|
||||
dev_err(master->dev, "Cannot handle such a list of devices\n");
|
||||
|
||||
rpm_out:
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue