I3C for 6.17

New driver:
  - Renesas I3C controller
 
 Subsystem:
  - use adapter timeout value for I2C transfers
  - don't fail if GETHDRCAP is unsupported
  - replace ENOTSUPP with SUSV4-compliant EOPNOTSUPP
 
 Drivers:
  - svc: Fix npcm845 FIFO_EMPTY quirk
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmiOnMkACgkQY6TcMGxw
 OjLNIBAAi5Snj3ZjHxO+MdLE27vsJq+gW7Pk0jxrG0bkPNOrbRtIjmuZNT+hPxZ+
 bqN3Vi/l5+iy8ZuZETYOabW7LG5nDKUF4M4RmewwtkkfXchRfsTQeCnVL8wDXdCp
 GYYBT0mPXU4+9F0vXVlezjTPuT9V/gry0SnsjK+NfegjmYZ/bFY+RExsYZQpeHut
 W6TPq5M+ytLnHqsx/bxfez4voxkir6vR+ydPO6reBGaxW8KUQmOki1mNTW4J4crs
 WZg+egFmnWFZjU8BUzjCkvgnvLqJws5oKg+4AlY5q4zPHMSuDAgRtjHprISEGcQc
 6LQZwZBx2YocgiuQo09jjX6q4FbRjaAbdZLAvtPOFUqX0SpeFZA1HJ3tmPEdmJ6S
 JwGVNjh2kda/SHqY0LlAojEApX9Z8z0C0dexR51YxWvnX8duwww0Rhhi/yvwWrzP
 rVIDgRXv9UAKk1sZG7/mRbpCJHtEwKlBOnU3DxQKjFnKVVazdnP6zOZjptxRkXBX
 tVxTB/HASjlA8EoncBh+vhq7Xm81+Py7VR02yY0dhdeLdgfKTVfdL8tVPf8cQ/bO
 6bo4vn1BgO4jyb4GW0ikB7tVVo4azYQcCNHvDB7zJ9Magv17FVW1bqnRVEvaprpx
 0Ty10paXD58vPgJNe03hiU91e2L05wpoggYuX3MQqe7UpkJKVkI=
 =cX/f
 -----END PGP SIGNATURE-----

Merge tag 'i3c/for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux

Pull i3c updates from Alexandre Belloni:
 "New driver:
   - Renesas I3C controller

  Subsystem:
   - use adapter timeout value for I2C transfers
   - don't fail if GETHDRCAP is unsupported
   - replace ENOTSUPP with SUSV4-compliant EOPNOTSUPP

  Drivers:
   - svc: Fix npcm845 FIFO_EMPTY quirk"

* tag 'i3c/for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: (25 commits)
  i3c: add missing include to internal header
  i3c: dw: Remove redundant pm_runtime_mark_last_busy() calls
  i3c: master: svc: Remove redundant pm_runtime_mark_last_busy() calls
  i3c: master: svc: Fix npcm845 FIFO_EMPTY quirk
  i3c: master: Add basic driver for the Renesas I3C controller
  dt-bindings: i3c: Add Renesas I3C controller
  i3c: Add more parameters for controllers to the header
  i3c: Standardize defines for specification parameters
  i3c: fix module_i3c_i2c_driver() with I3C=n
  i3c: master: cdns: Simplify handling clocks in probe()
  i3c: Fix i3c_device_do_priv_xfers() kernel-doc indentation
  i3c: master: dw: Use i3c_writel_fifo() and i3c_readl_fifo()
  i3c: master: cdns: Use i3c_writel_fifo() and i3c_readl_fifo()
  i3c: master: Add inline i3c_readl_fifo() and i3c_writel_fifo()
  i3c: prefix hexadecimal entries in sysfs
  i3c: master: cdns: replace ENOTSUPP with SUSV4-compliant EOPNOTSUPP
  i3c: dw: replace ENOTSUPP with SUSV4-compliant EOPNOTSUPP
  i3c: master: replace ENOTSUPP with SUSV4-compliant EOPNOTSUPP
  i3c: don't fail if GETHDRCAP is unsupported
  i3c: add patchwork entry to MAINTAINERS
  ...
This commit is contained in:
Linus Torvalds 2025-08-03 14:12:02 -07:00
commit 546b0ad6a8
14 changed files with 1727 additions and 148 deletions

View File

@ -0,0 +1,179 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i3c/renesas,i3c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/G3S and RZ/G3E I3C Bus Interface
maintainers:
- Wolfram Sang <wsa+renesas@sang-engineering.com>
- Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
properties:
compatible:
items:
- enum:
- renesas,r9a08g045-i3c # RZ/G3S
- renesas,r9a09g047-i3c # RZ/G3E
reg:
maxItems: 1
interrupts:
items:
- description: Non-recoverable internal error interrupt
- description: Normal transfer error interrupt
- description: Normal transfer abort interrupt
- description: Normal response status buffer full interrupt
- description: Normal command buffer empty interrupt
- description: Normal IBI status buffer full interrupt
- description: Normal Rx data buffer full interrupt
- description: Normal Tx data buffer empty interrupt
- description: Normal receive status buffer full interrupt
- description: START condition detection interrupt
- description: STOP condition detection interrupt
- description: Transmit end interrupt
- description: NACK detection interrupt
- description: Arbitration lost interrupt
- description: Timeout detection interrupt
- description: Wake-up condition detection interrupt
- description: HDR Exit Pattern detection interrupt
minItems: 16
interrupt-names:
items:
- const: ierr
- const: terr
- const: abort
- const: resp
- const: cmd
- const: ibi
- const: rx
- const: tx
- const: rcv
- const: st
- const: sp
- const: tend
- const: nack
- const: al
- const: tmo
- const: wu
- const: exit
minItems: 16
clocks:
items:
- description: APB bus clock
- description: transfer clock
- description: SFRs clock
minItems: 2
clock-names:
items:
- const: pclk
- const: tclk
- const: pclkrw
minItems: 2
power-domains:
maxItems: 1
resets:
items:
- description: Reset signal
- description: APB interface reset signal/SCAN reset signal
reset-names:
items:
- const: presetn
- const: tresetn
required:
- compatible
- reg
- interrupts
- interrupt-names
- clock-names
- clocks
- power-domains
- resets
- reset-names
allOf:
- $ref: i3c.yaml#
- if:
properties:
compatible:
contains:
const: renesas,r9a08g045-i3c
then:
properties:
clocks:
maxItems: 2
clock-names:
maxItems: 2
interrupts:
minItems: 17
interrupt-names:
minItems: 17
- if:
properties:
compatible:
contains:
const: renesas,r9a09g047-i3c
then:
properties:
clocks:
minItems: 3
clock-names:
minItems: 3
interrupts:
maxItems: 16
interrupt-names:
maxItems: 16
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/r9a08g045-cpg.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
i3c@1005b000 {
compatible = "renesas,r9a08g045-i3c";
reg = <0x1005b000 0x1000>;
clocks = <&cpg CPG_MOD R9A08G045_I3C_PCLK>,
<&cpg CPG_MOD R9A08G045_I3C_TCLK>;
clock-names = "pclk", "tclk";
interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 294 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 295 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 297 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 298 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 299 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "ierr", "terr", "abort", "resp",
"cmd", "ibi", "rx", "tx", "rcv",
"st", "sp", "tend", "nack",
"al", "tmo", "wu", "exit";
resets = <&cpg R9A08G045_I3C_PRESETN>,
<&cpg R9A08G045_I3C_TRESETN>;
reset-names = "presetn", "tresetn";
power-domains = <&cpg>;
#address-cells = <3>;
#size-cells = <0>;
};
...

View File

@ -11612,6 +11612,13 @@ S: Maintained
F: Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml
F: drivers/i3c/master/i3c-master-cdns.c
I3C DRIVER FOR RENESAS
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
M: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
S: Supported
F: Documentation/devicetree/bindings/i3c/renesas,i3c.yaml
F: drivers/i3c/master/renesas-i3c.c
I3C DRIVER FOR SYNOPSYS DESIGNWARE
S: Orphan
F: Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml
@ -11622,6 +11629,7 @@ M: Alexandre Belloni <alexandre.belloni@bootlin.com>
R: Frank Li <Frank.Li@nxp.com>
L: linux-i3c@lists.infradead.org (moderated for non-subscribers)
S: Maintained
Q: https://patchwork.kernel.org/project/linux-i3c/list/
C: irc://chat.freenode.net/linux-i3c
T: git git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git
F: Documentation/ABI/testing/sysfs-bus-i3c

View File

@ -26,11 +26,12 @@
*
* This function can sleep and thus cannot be called in atomic context.
*
* Return: 0 in case of success, a negative error core otherwise.
* -EAGAIN: controller lost address arbitration. Target
* (IBI, HJ or controller role request) win the bus. Client
* driver needs to resend the 'xfers' some time later.
* See I3C spec ver 1.1.1 09-Jun-2021. Section: 5.1.2.2.3.
* Return:
* * 0 in case of success, a negative error core otherwise.
* * -EAGAIN: controller lost address arbitration. Target (IBI, HJ or
* controller role request) win the bus. Client driver needs to resend the
* 'xfers' some time later. See I3C spec ver 1.1.1 09-Jun-2021. Section:
* 5.1.2.2.3.
*/
int i3c_device_do_priv_xfers(struct i3c_device *dev,
struct i3c_priv_xfer *xfers,

View File

@ -9,6 +9,7 @@
#define I3C_INTERNALS_H
#include <linux/i3c/master.h>
#include <linux/io.h>
void i3c_bus_normaluse_lock(struct i3c_bus *bus);
void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
@ -22,4 +23,41 @@ int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev);
int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
const struct i3c_ibi_setup *req);
void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev);
/**
* i3c_writel_fifo - Write data buffer to 32bit FIFO
* @addr: FIFO Address to write to
* @buf: Pointer to the data bytes to write
* @nbytes: Number of bytes to write
*/
static inline void i3c_writel_fifo(void __iomem *addr, const void *buf,
int nbytes)
{
writesl(addr, buf, nbytes / 4);
if (nbytes & 3) {
u32 tmp = 0;
memcpy(&tmp, buf + (nbytes & ~3), nbytes & 3);
writel(tmp, addr);
}
}
/**
* i3c_readl_fifo - Read data buffer from 32bit FIFO
* @addr: FIFO Address to read from
* @buf: Pointer to the buffer to store read bytes
* @nbytes: Number of bytes to read
*/
static inline void i3c_readl_fifo(const void __iomem *addr, void *buf,
int nbytes)
{
readsl(addr, buf, nbytes / 4);
if (nbytes & 3) {
u32 tmp;
tmp = readl(addr);
memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
}
}
#endif /* I3C_INTERNAL_H */

View File

@ -141,7 +141,7 @@ static ssize_t bcr_show(struct device *dev,
i3c_bus_normaluse_lock(bus);
desc = dev_to_i3cdesc(dev);
ret = sprintf(buf, "%x\n", desc->info.bcr);
ret = sprintf(buf, "0x%02x\n", desc->info.bcr);
i3c_bus_normaluse_unlock(bus);
return ret;
@ -158,7 +158,7 @@ static ssize_t dcr_show(struct device *dev,
i3c_bus_normaluse_lock(bus);
desc = dev_to_i3cdesc(dev);
ret = sprintf(buf, "%x\n", desc->info.dcr);
ret = sprintf(buf, "0x%02x\n", desc->info.dcr);
i3c_bus_normaluse_unlock(bus);
return ret;
@ -727,12 +727,12 @@ static int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode,
switch (i3cbus->mode) {
case I3C_BUS_MODE_PURE:
if (!i3cbus->scl_rate.i3c)
i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
i3cbus->scl_rate.i3c = I3C_BUS_I3C_SCL_TYP_RATE;
break;
case I3C_BUS_MODE_MIXED_FAST:
case I3C_BUS_MODE_MIXED_LIMITED:
if (!i3cbus->scl_rate.i3c)
i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
i3cbus->scl_rate.i3c = I3C_BUS_I3C_SCL_TYP_RATE;
if (!i3cbus->scl_rate.i2c)
i3cbus->scl_rate.i2c = max_i2c_scl_rate;
break;
@ -754,8 +754,8 @@ static int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode,
* I3C/I2C frequency may have been overridden, check that user-provided
* values are not exceeding max possible frequency.
*/
if (i3cbus->scl_rate.i3c > I3C_BUS_MAX_I3C_SCL_RATE ||
i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_RATE)
if (i3cbus->scl_rate.i3c > I3C_BUS_I3C_SCL_MAX_RATE ||
i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE)
return -EINVAL;
return 0;
@ -837,14 +837,14 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master,
return -EINVAL;
if (!master->ops->send_ccc_cmd)
return -ENOTSUPP;
return -EOPNOTSUPP;
if ((cmd->id & I3C_CCC_DIRECT) && (!cmd->dests || !cmd->ndests))
return -EINVAL;
if (master->ops->supports_ccc_cmd &&
!master->ops->supports_ccc_cmd(master, cmd))
return -ENOTSUPP;
return -EOPNOTSUPP;
ret = master->ops->send_ccc_cmd(master, cmd);
if (ret) {
@ -1439,7 +1439,7 @@ static int i3c_master_retrieve_dev_info(struct i3c_dev_desc *dev)
if (dev->info.bcr & I3C_BCR_HDR_CAP) {
ret = i3c_master_gethdrcap_locked(master, &dev->info);
if (ret)
if (ret && ret != -EOPNOTSUPP)
return ret;
}
@ -2210,7 +2210,7 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
*/
if (boardinfo->base.flags & I2C_CLIENT_TEN) {
dev_err(dev, "I2C device with 10 bit address not supported.");
return -ENOTSUPP;
return -EOPNOTSUPP;
}
/* LVR is encoded in reg[2]. */
@ -2340,13 +2340,13 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
return -EINVAL;
if (!master->ops->i2c_xfers)
return -ENOTSUPP;
return -EOPNOTSUPP;
/* Doing transfers to different devices is not supported. */
addr = xfers[0].addr;
for (i = 1; i < nxfers; i++) {
if (addr != xfers[i].addr)
return -ENOTSUPP;
return -EOPNOTSUPP;
}
i3c_bus_normaluse_lock(&master->bus);
@ -2467,6 +2467,8 @@ static int i3c_i2c_notifier_call(struct notifier_block *nb, unsigned long action
case BUS_NOTIFY_DEL_DEVICE:
ret = i3c_master_i2c_detach(adap, client);
break;
default:
ret = -EINVAL;
}
i3c_bus_maintenance_unlock(&master->bus);
@ -2766,7 +2768,7 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
* controller)
* @ops: the master controller operations
* @secondary: true if you are registering a secondary master. Will return
* -ENOTSUPP if set to true since secondary masters are not yet
* -EOPNOTSUPP if set to true since secondary masters are not yet
* supported
*
* This function takes care of everything for you:
@ -2785,7 +2787,7 @@ int i3c_master_register(struct i3c_master_controller *master,
const struct i3c_master_controller_ops *ops,
bool secondary)
{
unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE;
unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE;
struct i3c_bus *i3cbus = i3c_master_get_bus(master);
enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
struct i2c_dev_boardinfo *i2cbi;
@ -2793,7 +2795,7 @@ int i3c_master_register(struct i3c_master_controller *master,
/* We do not support secondary masters yet. */
if (secondary)
return -ENOTSUPP;
return -EOPNOTSUPP;
ret = i3c_master_check_ops(ops);
if (ret)
@ -2844,7 +2846,7 @@ int i3c_master_register(struct i3c_master_controller *master,
}
if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE)
i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE;
i2c_scl_rate = I3C_BUS_I2C_FM_SCL_MAX_RATE;
}
ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate);
@ -2954,7 +2956,7 @@ int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
return -EINVAL;
if (!master->ops->priv_xfers)
return -ENOTSUPP;
return -EOPNOTSUPP;
return master->ops->priv_xfers(dev, xfers, nxfers);
}
@ -3004,7 +3006,7 @@ int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
int ret;
if (!master->ops->request_ibi)
return -ENOTSUPP;
return -EOPNOTSUPP;
if (dev->ibi)
return -EBUSY;

View File

@ -64,3 +64,13 @@ config MIPI_I3C_HCI_PCI
This driver can also be built as a module. If so, the module will be
called mipi-i3c-hci-pci.
config RENESAS_I3C
tristate "Renesas I3C controller driver"
depends on HAS_IOMEM
depends on ARCH_RENESAS || COMPILE_TEST
help
Support the Renesas I3C controller as found in some RZ variants.
This driver can also be built as a module. If so, the module will be
called renesas-i3c.

View File

@ -4,3 +4,4 @@ obj-$(CONFIG_DW_I3C_MASTER) += dw-i3c-master.o
obj-$(CONFIG_AST2600_I3C_MASTER) += ast2600-i3c-master.o
obj-$(CONFIG_SVC_I3C_MASTER) += svc-i3c-master.o
obj-$(CONFIG_MIPI_I3C_HCI) += mipi-i3c-hci/
obj-$(CONFIG_RENESAS_I3C) += renesas-i3c.o

View File

@ -23,6 +23,7 @@
#include <linux/reset.h>
#include <linux/slab.h>
#include "../internals.h"
#include "dw-i3c-master.h"
#define DEVICE_CTRL 0x0
@ -336,37 +337,19 @@ static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master)
static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master,
const u8 *bytes, int nbytes)
{
writesl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4);
if (nbytes & 3) {
u32 tmp = 0;
memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
writesl(master->regs + RX_TX_DATA_PORT, &tmp, 1);
}
}
static void dw_i3c_master_read_fifo(struct dw_i3c_master *master,
int reg, u8 *bytes, int nbytes)
{
readsl(master->regs + reg, bytes, nbytes / 4);
if (nbytes & 3) {
u32 tmp;
readsl(master->regs + reg, &tmp, 1);
memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
}
i3c_writel_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes);
}
static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master,
u8 *bytes, int nbytes)
{
return dw_i3c_master_read_fifo(master, RX_TX_DATA_PORT, bytes, nbytes);
i3c_readl_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes);
}
static void dw_i3c_master_read_ibi_fifo(struct dw_i3c_master *master,
u8 *bytes, int nbytes)
{
return dw_i3c_master_read_fifo(master, IBI_QUEUE_STATUS, bytes, nbytes);
i3c_readl_fifo(master->regs + IBI_QUEUE_STATUS, bytes, nbytes);
}
static struct dw_i3c_xfer *
@ -622,14 +605,14 @@ static int dw_i2c_clk_cfg(struct dw_i3c_master *master)
core_period = DIV_ROUND_UP(1000000000, core_rate);
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS, core_period);
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt;
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE) - lcnt;
scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) |
SCL_I2C_FMP_TIMING_LCNT(lcnt);
writel(scl_timing, master->regs + SCL_I2C_FMP_TIMING);
master->i2c_fmp_timing = scl_timing;
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS, core_period);
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt;
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_MAX_RATE) - lcnt;
scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) |
SCL_I2C_FM_TIMING_LCNT(lcnt);
writel(scl_timing, master->regs + SCL_I2C_FM_TIMING);
@ -699,7 +682,6 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
dw_i3c_master_enable(master);
rpm_out:
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@ -829,7 +811,6 @@ static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
else
ret = dw_i3c_ccc_set(master, ccc);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@ -912,7 +893,6 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
dw_i3c_master_free_xfer(xfer);
rpm_out:
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@ -932,7 +912,7 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
return 0;
if (i3c_nxfers > master->caps.cmdfifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
for (i = 0; i < i3c_nxfers; i++) {
if (i3c_xfers[i].rnw)
@ -943,7 +923,7 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
if (ntxwords > master->caps.datafifodepth ||
nrxwords > master->caps.datafifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
if (!xfer)
@ -998,7 +978,6 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
ret = xfer->ret;
dw_i3c_master_free_xfer(xfer);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@ -1093,7 +1072,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
return 0;
if (i2c_nxfers > master->caps.cmdfifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
for (i = 0; i < i2c_nxfers; i++) {
if (i2c_xfers[i].flags & I2C_M_RD)
@ -1104,7 +1083,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
if (ntxwords > master->caps.datafifodepth ||
nrxwords > master->caps.datafifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers);
if (!xfer)
@ -1142,13 +1121,12 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
}
dw_i3c_master_enqueue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
dw_i3c_master_dequeue_xfer(master, xfer);
ret = xfer->ret;
dw_i3c_master_free_xfer(xfer);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@ -1316,7 +1294,6 @@ static int dw_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK,
master->regs + DEVICE_CTRL);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return 0;
}
@ -1342,7 +1319,6 @@ static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
if (rc) {
dw_i3c_master_set_sir_enabled(master, dev, data->index, false);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
}
@ -1362,7 +1338,6 @@ static int dw_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
dw_i3c_master_set_sir_enabled(master, dev, data->index, false);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return 0;
}

View File

@ -23,6 +23,8 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include "../internals.h"
#define DEV_ID 0x0
#define DEV_ID_I3C_MASTER 0x5034
@ -412,7 +414,6 @@ struct cdns_i3c_master {
} xferqueue;
void __iomem *regs;
struct clk *sysclk;
struct clk *pclk;
struct cdns_i3c_master_caps caps;
unsigned long i3c_scl_lim;
const struct cdns_i3c_data *devdata;
@ -427,25 +428,13 @@ to_cdns_i3c_master(struct i3c_master_controller *master)
static void cdns_i3c_master_wr_to_tx_fifo(struct cdns_i3c_master *master,
const u8 *bytes, int nbytes)
{
writesl(master->regs + TX_FIFO, bytes, nbytes / 4);
if (nbytes & 3) {
u32 tmp = 0;
memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
writesl(master->regs + TX_FIFO, &tmp, 1);
}
i3c_writel_fifo(master->regs + TX_FIFO, bytes, nbytes);
}
static void cdns_i3c_master_rd_from_rx_fifo(struct cdns_i3c_master *master,
u8 *bytes, int nbytes)
{
readsl(master->regs + RX_FIFO, bytes, nbytes / 4);
if (nbytes & 3) {
u32 tmp;
readsl(master->regs + RX_FIFO, &tmp, 1);
memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
}
i3c_readl_fifo(master->regs + RX_FIFO, bytes, nbytes);
}
static bool cdns_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
@ -742,7 +731,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
for (i = 0; i < nxfers; i++) {
if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
return -ENOTSUPP;
return -EOPNOTSUPP;
}
if (!nxfers)
@ -750,7 +739,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
if (nxfers > master->caps.cmdfifodepth ||
nxfers > master->caps.cmdrfifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
/*
* First make sure that all transactions (block of transfers separated
@ -765,7 +754,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
if (rxslots > master->caps.rxfifodepth ||
txslots > master->caps.txfifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
cdns_xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
if (!cdns_xfer)
@ -822,11 +811,11 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
int i, ret = 0;
if (nxfers > master->caps.cmdfifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
for (i = 0; i < nxfers; i++) {
if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
return -ENOTSUPP;
return -EOPNOTSUPP;
if (xfers[i].flags & I2C_M_RD)
nrxwords += DIV_ROUND_UP(xfers[i].len, 4);
@ -836,7 +825,7 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
if (ntxwords > master->caps.txfifodepth ||
nrxwords > master->caps.rxfifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
if (!xfer)
@ -863,7 +852,7 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
}
cdns_i3c_master_queue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
cdns_i3c_master_unqueue_xfer(master, xfer);
ret = xfer->ret;
@ -1330,12 +1319,7 @@ static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
buf = slot->data;
nbytes = IBIR_XFER_BYTES(ibir);
readsl(master->regs + IBI_DATA_FIFO, buf, nbytes / 4);
if (nbytes % 3) {
u32 tmp = __raw_readl(master->regs + IBI_DATA_FIFO);
memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
}
i3c_readl_fifo(master->regs + IBI_DATA_FIFO, buf, nbytes);
slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir),
dev->ibi->max_payload_len);
@ -1566,6 +1550,7 @@ MODULE_DEVICE_TABLE(of, cdns_i3c_master_of_ids);
static int cdns_i3c_master_probe(struct platform_device *pdev)
{
struct cdns_i3c_master *master;
struct clk *pclk;
int ret, irq;
u32 val;
@ -1581,11 +1566,11 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
if (IS_ERR(master->regs))
return PTR_ERR(master->regs);
master->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(master->pclk))
return PTR_ERR(master->pclk);
pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
if (IS_ERR(pclk))
return PTR_ERR(pclk);
master->sysclk = devm_clk_get(&pdev->dev, "sysclk");
master->sysclk = devm_clk_get_enabled(&pdev->dev, "sysclk");
if (IS_ERR(master->sysclk))
return PTR_ERR(master->sysclk);
@ -1593,18 +1578,8 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
ret = clk_prepare_enable(master->pclk);
if (ret)
return ret;
ret = clk_prepare_enable(master->sysclk);
if (ret)
goto err_disable_pclk;
if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER) {
ret = -EINVAL;
goto err_disable_sysclk;
}
if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER)
return -EINVAL;
spin_lock_init(&master->xferqueue.lock);
INIT_LIST_HEAD(&master->xferqueue.list);
@ -1615,7 +1590,7 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0,
dev_name(&pdev->dev), master);
if (ret)
goto err_disable_sysclk;
return ret;
platform_set_drvdata(pdev, master);
@ -1637,29 +1612,15 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
sizeof(*master->ibi.slots),
GFP_KERNEL);
if (!master->ibi.slots) {
ret = -ENOMEM;
goto err_disable_sysclk;
}
if (!master->ibi.slots)
return -ENOMEM;
writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL);
writel(MST_INT_IBIR_THR, master->regs + MST_IER);
writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
ret = i3c_master_register(&master->base, &pdev->dev,
&cdns_i3c_master_ops, false);
if (ret)
goto err_disable_sysclk;
return 0;
err_disable_sysclk:
clk_disable_unprepare(master->sysclk);
err_disable_pclk:
clk_disable_unprepare(master->pclk);
return ret;
return i3c_master_register(&master->base, &pdev->dev,
&cdns_i3c_master_ops, false);
}
static void cdns_i3c_master_remove(struct platform_device *pdev)
@ -1668,9 +1629,6 @@ static void cdns_i3c_master_remove(struct platform_device *pdev)
cancel_work_sync(&master->hj_work);
i3c_master_unregister(&master->base);
clk_disable_unprepare(master->sysclk);
clk_disable_unprepare(master->pclk);
}
static struct platform_driver cdns_i3c_master = {

View File

@ -395,7 +395,7 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
ret = hci->io->queue_xfer(hci, xfer, nxfers);
if (ret)
goto out;
if (!wait_for_completion_timeout(&done, HZ) &&
if (!wait_for_completion_timeout(&done, m->i2c.timeout) &&
hci->io->dequeue_xfer(hci, xfer, nxfers)) {
ret = -ETIME;
goto out;

File diff suppressed because it is too large Load Diff

View File

@ -104,6 +104,7 @@
#define SVC_I3C_MDATACTRL_TXTRIG_FIFO_NOT_FULL GENMASK(5, 4)
#define SVC_I3C_MDATACTRL_RXTRIG_FIFO_NOT_EMPTY 0
#define SVC_I3C_MDATACTRL_RXCOUNT(x) FIELD_GET(GENMASK(28, 24), (x))
#define SVC_I3C_MDATACTRL_TXCOUNT(x) FIELD_GET(GENMASK(20, 16), (x))
#define SVC_I3C_MDATACTRL_TXFULL BIT(30)
#define SVC_I3C_MDATACTRL_RXEMPTY BIT(31)
@ -664,7 +665,6 @@ static int svc_i3c_master_set_speed(struct i3c_master_controller *m,
}
rpm_out:
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
@ -779,7 +779,6 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
goto rpm_out;
rpm_out:
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
@ -801,7 +800,6 @@ static void svc_i3c_master_bus_cleanup(struct i3c_master_controller *m)
/* Disable master */
writel(0, master->regs + SVC_I3C_MCONFIG);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
}
@ -1207,7 +1205,6 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
dev_err(master->dev, "Cannot handle such a list of devices");
rpm_out:
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
@ -1304,14 +1301,19 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
* FIFO start filling as soon as possible after EmitStartAddr.
*/
if (svc_has_quirk(master, SVC_I3C_QUIRK_FIFO_EMPTY) && !rnw && xfer_len) {
u32 end = xfer_len > SVC_I3C_FIFO_SIZE ? 0 : SVC_I3C_MWDATAB_END;
u32 len = min_t(u32, xfer_len, SVC_I3C_FIFO_SIZE);
u32 space, end, len;
writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
/* Mark END bit if this is the last byte */
writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
xfer_len -= len;
out += len;
reg = readl(master->regs + SVC_I3C_MDATACTRL);
space = SVC_I3C_FIFO_SIZE - SVC_I3C_MDATACTRL_TXCOUNT(reg);
if (space) {
end = xfer_len > space ? 0 : SVC_I3C_MWDATAB_END;
len = min_t(u32, xfer_len, space);
writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
/* Mark END bit if this is the last byte */
writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
xfer_len -= len;
out += len;
}
}
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
@ -1511,7 +1513,6 @@ static void svc_i3c_master_enqueue_xfer(struct svc_i3c_master *master,
}
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
}
@ -1708,7 +1709,7 @@ static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
mutex_lock(&master->lock);
svc_i3c_master_enqueue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
svc_i3c_master_dequeue_xfer(master, xfer);
mutex_unlock(&master->lock);
@ -1801,7 +1802,6 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
@ -1834,7 +1834,6 @@ static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
if (!master->enabled_events)
svc_i3c_master_disable_interrupts(master);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return 0;
@ -1954,7 +1953,6 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
if (ret)
goto rpm_disable;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;

View File

@ -245,7 +245,7 @@ void i3c_driver_unregister(struct i3c_driver *drv);
*
* Return: 0 if both registrations succeeds, a negative error code otherwise.
*/
static inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
static __always_inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
struct i2c_driver *i2cdrv)
{
int ret;
@ -270,7 +270,7 @@ static inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
* Note that when CONFIG_I3C is not enabled, this function only unregisters the
* @i2cdrv.
*/
static inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
static __always_inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
struct i2c_driver *i2cdrv)
{
if (IS_ENABLED(CONFIG_I3C))

View File

@ -249,10 +249,15 @@ struct i3c_device {
*/
#define I3C_BUS_MAX_DEVS 11
#define I3C_BUS_MAX_I3C_SCL_RATE 12900000
#define I3C_BUS_TYP_I3C_SCL_RATE 12500000
#define I3C_BUS_I2C_FM_PLUS_SCL_RATE 1000000
#define I3C_BUS_I2C_FM_SCL_RATE 400000
/* Taken from the I3C Spec V1.1.1, chapter 6.2. "Timing specification" */
#define I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE 1000000
#define I3C_BUS_I2C_FM_SCL_MAX_RATE 400000
#define I3C_BUS_I3C_SCL_MAX_RATE 12900000
#define I3C_BUS_I3C_SCL_TYP_RATE 12500000
#define I3C_BUS_TAVAL_MIN_NS 1000
#define I3C_BUS_TBUF_MIXED_FM_MIN_NS 1300
#define I3C_BUS_THIGH_MIXED_MAX_NS 41
#define I3C_BUS_TIDLE_MIN_NS 200000
#define I3C_BUS_TLOW_OD_MIN_NS 200
/**