Commit 546b0ad6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
  ...
parents 352af6a0 3b661ca5
Loading
Loading
Loading
Loading
+179 −0
Original line number Diff line number Diff line
# 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>;
    };
...
+8 −0
Original line number Diff line number Diff line
@@ -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
+6 −5
Original line number Diff line number Diff line
@@ -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,
+38 −0
Original line number Diff line number Diff line
@@ -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 */
+20 −18
Original line number Diff line number Diff line
@@ -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;
Loading