Skip to contentSkip to conversation

i3c: Add support for ast2600 i3c controller

PATCH New Jeremy Kerr 5 participants 10 messages Feb 16, 2023 – Mar 1, 2023

Subsystems (5)
lore
Share & tools
lore

Jeremy Kerr

author maintainer
#0 lore raw

cover i3c: Add support for ast2600 i3c controller

The AST2600 SoC hardware includes a set of i3c controllers, based on the designware i3c core, plus some global registers for SoC integration.

This series adds support for these i3c controllers, through the existing dw i3c master controller driver, by adding a set of platform-specific hooks to handle the global register configuration. This also gives us a way to add any future hardware-specific behaviours.

We also need a DT binding to describe the ast2600-specific hardware. Since this involves new (mandatory) properties, I have added this as a separate binding rather than add a new compat string to the dw binding.

The dt-binding example depends on a prior submission to the dt binding headers:

https://lore.kernel.org/linux-devicetree/cover.1676294433.git.jk at codeconstruct.com.au/

Full support for the global regmap will land with this queued mfd change:

https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git/commit/?id=cf2271843de835839e91c5c036492a87085af756

Of course, any queries/comments/etc are most welcome.

Cheers,

Jeremy

Jeremy Kerr (4):
dt-bindings: i3c: Add AST2600 i3c controller
i3c: dw: Add platform operations
i3c: dw: Add AST2600 platform ops
i3c: dw: Add compatible string for ASPEED AST2600 BMC platform

 .../bindings/i3c/aspeed,ast2600-i3c.yaml      |  73 ++++++++
 drivers/i3c/master/dw-i3c-master.c            | 165 +++++++++++++++++-
 2 files changed, 232 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml
Signature · 1 line
2.39.1
author maintainer
#1 lore raw

PATCH 1/4 dt-bindings: i3c: Add AST2600 i3c controller

Add a devicetree binding for the ast2600 i3c controller hardware. This is heavily based on the designware i3c core, plus a reset facility and two platform-specific properties:

- sda-pullup-ohms: to specify the value of the configurable pullup resistors on the SDA line

- aspeed,global-regs: to reference the (ast2600-specific) i3c global register block, and the device index to use within it.

---
changes from RFC:
- add vendor prefix to global-regs properties
- add item description on global-regs property
- drop global reg node from example

---
 .../bindings/i3c/aspeed,ast2600-i3c.yaml      | 73 +++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml
Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml new file +73 -0
new file mode 100644
index 000000000000..920428f243b5
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i3c/aspeed,ast2600-i3c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED AST2600 i3c controller
+
+maintainers:
+  - Jeremy Kerr <[email protected]>
+
+allOf:
+  - $ref: i3c.yaml#
+
+properties:
+  compatible:
+    const: aspeed,ast2600-i3c
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  sda-pullup-ohms:
+    enum: [545, 750, 2000]
+    default: 2000
+    description: |
+      Value to configure SDA pullup resistor, in Ohms.
+
+  aspeed,global-regs:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: phandle to i3c global register syscon node
+          - description: index of this i3c controller in the global register set
+    description: |
+      A (phandle, controller index) reference to the i3c global register set
+      used for this device.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - interrupts
+  - aspeed,global-regs
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/ast2600-clock.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    i3c-master at 2000 {
+        compatible = "aspeed,ast2600-i3c";
+        reg = <0x2000 0x1000>;
+        #address-cells = <3>;
+        #size-cells = <0>;
+        clocks = <&syscon ASPEED_CLK_GATE_I3C0CLK>;
+        resets = <&syscon ASPEED_RESET_I3C0>;
+        aspeed,global-regs = <&i3c_global 0>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_i3c1_default>;
+        interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+    };
+...
Signature · 1 line
2.39.1
#2 lore raw

PATCH 1/4 dt-bindings: i3c: Add AST2600 i3c controller

Quoted 4 lines · Jeremy Kerr

Add a devicetree binding for the ast2600 i3c controller hardware. This is heavily based on the designware i3c core, plus a reset facility and two platform-specific properties:

Quoted 8 lines

- sda-pullup-ohms: to specify the value of the configurable pullup resistors on the SDA line

- aspeed,global-regs: to reference the (ast2600-specific) i3c global register block, and the device index to use within it.

Best regards,
Krzysztof

maintainer
#3 lore raw

PATCH 1/4 dt-bindings: i3c: Add AST2600 i3c controller

In reply to Jeremy Kerr
Quoted 17 lines · Jeremy Kerr

Add a devicetree binding for the ast2600 i3c controller hardware. This is heavily based on the designware i3c core, plus a reset facility and two platform-specific properties:

- sda-pullup-ohms: to specify the value of the configurable pullup resistors on the SDA line

- aspeed,global-regs: to reference the (ast2600-specific) i3c global register block, and the device index to use within it.

---
changes from RFC:
- add vendor prefix to global-regs properties
- add item description on global-regs property
- drop global reg node from example

Quoted 5 lines
---
 .../bindings/i3c/aspeed,ast2600-i3c.yaml      | 73 +++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Error: Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.example.dts:30.31-32 syntax error FATAL ERROR: Unable to parse input tree
make[1]: *** [scripts/Makefile.lib:434: Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.example.dtb] Error 1 make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:1508: dt_binding_check] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/82d750f53df622d8986e9a07053c7ee27dee61a2.1676532146.git.jk at codeconstruct.com.au

The base for the series is generally the latest rc1. A different dependency should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note that DT_SCHEMA_FILES can be set to your schema file to speed up checking your schema. However, it must be unset to test all examples with your schema.

author maintainer
#4 lore raw

PATCH 2/4 i3c: dw: Add platform operations

In reply to Jeremy Kerr

The dw i3c core can be integrated into various SoC devices. Platforms that use this core may need a little configuration that is specific to that platform.

Add a little infrastructure to allow platform-specific behaviour: a bit of data on struct dw_i3c_master, and two hooks to the probe and init calls to enable this.

A future change will add new platform support that uses these hooks.

---
 drivers/i3c/master/dw-i3c-master.c | 42 +++++++++++++++++++++++++-----
 1 file changed, 36 insertions(+), 6 deletions(-)
drivers/i3c/master/dw-i3c-master.c +36 -6
index d73d57362b3b..49b891449222 100644
@@ -241,6 +241,17 @@ struct dw_i3c_master {
 	char version[5];
 	char type[5];
 	u8 addrs[MAX_DEVS];
+
+	/* platform-specific data */
+	const struct dw_i3c_platform_ops *platform_ops;
+	union {
+	} pdata;
+
+};
+
+struct dw_i3c_platform_ops {
+	int (*probe)(struct dw_i3c_master *i3c, struct platform_device *pdev);
+	int (*init)(struct dw_i3c_master *i3c);
 };
 
 struct dw_i3c_i2c_dev_data {
@@ -612,6 +623,12 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 	u32 thld_ctrl;
 	int ret;
 
+	if (master->platform_ops && master->platform_ops->init) {
+		ret = master->platform_ops->init(master);
+		if (ret)
+			return ret;
+	}
+
 	switch (bus->mode) {
 	case I3C_BUS_MODE_MIXED_FAST:
 	case I3C_BUS_MODE_MIXED_LIMITED:
@@ -1128,8 +1145,15 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
 	.i2c_xfers = dw_i3c_master_i2c_xfers,
 };
 
+static const struct of_device_id dw_i3c_master_of_match[] = {
+	{ .compatible = "snps,dw-i3c-master-1.00a", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
+
 static int dw_i3c_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *match;
 	struct dw_i3c_master *master;
 	int ret, irq;
 
@@ -1181,6 +1205,18 @@ static int dw_i3c_probe(struct platform_device *pdev)
 	master->maxdevs = ret >> 16;
 	master->free_pos = GENMASK(master->maxdevs - 1, 0);
 
+	/* match any platform-specific ops */
+	match = of_match_node(dw_i3c_master_of_match, pdev->dev.of_node);
+	if (match && match->data)
+		master->platform_ops = match->data;
+
+	/* platform-specific probe */
+	if (master->platform_ops && master->platform_ops->probe) {
+		ret = master->platform_ops->probe(master, pdev);
+		if (ret)
+			goto err_assert_rst;
+	}
+
 	ret = i3c_master_register(&master->base, &pdev->dev,
 				  &dw_mipi_i3c_ops, false);
 	if (ret)
@@ -1213,12 +1249,6 @@ static int dw_i3c_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id dw_i3c_master_of_match[] = {
-	{ .compatible = "snps,dw-i3c-master-1.00a", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
-
 static struct platform_driver dw_i3c_driver = {
 	.probe = dw_i3c_probe,
 	.remove = dw_i3c_remove,
Signature · 1 line
2.39.1
#5 lore raw

PATCH 2/4 i3c: dw: Add platform operations

Quoted 25 lines · Jeremy Kerr

The dw i3c core can be integrated into various SoC devices. Platforms that use this core may need a little configuration that is specific to that platform.

Add a little infrastructure to allow platform-specific behaviour: a bit of data on struct dw_i3c_master, and two hooks to the probe and init calls to enable this.

A future change will add new platform support that uses these hooks.

---
  drivers/i3c/master/dw-i3c-master.c | 42 +++++++++++++++++++++++++-----
  1 file changed, 36 insertions(+), 6 deletions(-)
drivers/i3c/master/dw-i3c-master.c +2 -0
index d73d57362b3b..49b891449222 100644
@@ -241,6 +241,17 @@ struct dw_i3c_master {
  	char version[5];
  	char type[5];
  	u8 addrs[MAX_DEVS];
+
+	/* platform-specific data */

drivers/i3c/master/dw-i3c-master.c struct dw_i3c_master { · line 255

Quoted 10 lines
drivers/i3c/master/dw-i3c-master.c +9 -0
+	const struct dw_i3c_platform_ops *platform_ops;
+	union {
+	} pdata;
+
+};
+
+struct dw_i3c_platform_ops {
+	int (*probe)(struct dw_i3c_master *i3c, struct platform_device *pdev);
+	int (*init)(struct dw_i3c_master *i3c);
  };

Given the comment below having this and the main probe defined in a header so users can just call in and we don't have to change the main code here every time someone comes up with their own special way of handing this?

drivers/i3c/master/dw-i3c-master.c static int dw_i3c_master_bus_init(struct i3c_master_controller *m) · line 630

Quoted 10 lines
drivers/i3c/master/dw-i3c-master.c +5 -0
  struct dw_i3c_i2c_dev_data {
@@ -612,6 +623,12 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
  	u32 thld_ctrl;
  	int ret;
 
+	if (master->platform_ops && master->platform_ops->init) {
+		ret = master->platform_ops->init(master);
+		if (ret)
+			return ret;
+	}

I'd rather have a "default" set of ops than have all this checking for NULL pointers all over the place.

Quoted 21 lines
drivers/i3c/master/dw-i3c-master.c +8 -0
+
  	switch (bus->mode) {
  	case I3C_BUS_MODE_MIXED_FAST:
  	case I3C_BUS_MODE_MIXED_LIMITED:
@@ -1128,8 +1145,15 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
  	.i2c_xfers = dw_i3c_master_i2c_xfers,
  };
 
+static const struct of_device_id dw_i3c_master_of_match[] = {
+	{ .compatible = "snps,dw-i3c-master-1.00a", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
+
  static int dw_i3c_probe(struct platform_device *pdev)
  {
+	const struct of_device_id *match;
  	struct dw_i3c_master *master;
  	int ret, irq;
 

drivers/i3c/master/dw-i3c-master.c static int dw_i3c_probe(struct platform_device *pdev) · line 1211

Quoted 7 lines
drivers/i3c/master/dw-i3c-master.c +4 -0
@@ -1181,6 +1205,18 @@ static int dw_i3c_probe(struct platform_device *pdev)
  	master->maxdevs = ret >> 16;
  	master->free_pos = GENMASK(master->maxdevs - 1, 0);
 
+	/* match any platform-specific ops */
+	match = of_match_node(dw_i3c_master_of_match, pdev->dev.of_node);
+	if (match && match->data)
+		master->platform_ops = match->data;

I'm sure there's a of_device_get_match_data() which would have both removed hte need to move the match table around and the call to of_match_node().

Quoted 24 lines
drivers/i3c/master/dw-i3c-master.c +8 -6
+
+	/* platform-specific probe */
+	if (master->platform_ops && master->platform_ops->probe) {
+		ret = master->platform_ops->probe(master, pdev);
+		if (ret)
+			goto err_assert_rst;
+	}
+
  	ret = i3c_master_register(&master->base, &pdev->dev,
  				  &dw_mipi_i3c_ops, false);
  	if (ret)
@@ -1213,12 +1249,6 @@ static int dw_i3c_remove(struct platform_device *pdev)
  	return 0;
  }
 
-static const struct of_device_id dw_i3c_master_of_match[] = {
-	{ .compatible = "snps,dw-i3c-master-1.00a", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
-
  static struct platform_driver dw_i3c_driver = {
  	.probe = dw_i3c_probe,
  	.remove = dw_i3c_remove,
author maintainer
#6 lore raw

PATCH 2/4 i3c: dw: Add platform operations

Hi Ben,

Thanks for taking a look at the patch. My responses inline (just re-ordered, simple stuff first)

Quoted 5 lines
Quoted 5 lines

? struct dw_i3c_i2c_dev_data {

(quoted diff) +0 -0
@@ -612,6 +623,12 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 ????????u32 thld_ctrl;
 ????????int ret;

?

Quoted 8 lines
Quoted 5 lines

+???????if (master->platform_ops && master->platform_ops->init) { +???????????????ret = master->platform_ops->init(master); +???????????????if (ret)
+???????????????????????return ret;
+???????}

I'd rather have a "default" set of ops than have all this checking for NULL pointers all over the place.

Yep, that's a better structure, changed for v2.

Quoted 4 lines
Quoted 4 lines
(quoted diff) +0 -0
@@ -1181,6 +1205,18 @@ static int dw_i3c_probe(struct platform_device *pdev)
 ????????master->maxdevs = ret >> 16;
 ????????master->free_pos = GENMASK(master->maxdevs - 1, 0);

?

Quoted 8 lines
Quoted 4 lines

+???????/* match any platform-specific ops */
+???????match = of_match_node(dw_i3c_master_of_match, pdev->dev.of_node); +???????if (match && match->data) +???????????????master->platform_ops = match->data;

I'm sure there's a of_device_get_match_data() which would have both removed hte need to move the match table around and the call to of_match_node().

That's the one I was looking for! Thanks for the pointer, I have updated in v2.

Quoted 13 lines
Quoted 13 lines
(quoted diff) +9 -0
@@ -241,6 +241,17 @@ struct dw_i3c_master {
 ????????char version[5];
 ????????char type[5];
 ????????u8 addrs[MAX_DEVS];
+
+???????/* platform-specific data */
+???????const struct dw_i3c_platform_ops *platform_ops;
+???????union {
+???????} pdata;
+
+};
+
+struct dw_i3c_platform_ops {
Quoted 8 lines

Review struct dw_i3c_master { · line 255

Quoted 3 lines
(quoted diff) +2 -0
+???????int (*probe)(struct dw_i3c_master *i3c, struct platform_device *pdev);
+???????int (*init)(struct dw_i3c_master *i3c);
 ? };

Given the comment below having this and the main probe defined in a header so users can just call in and we don't have to change the main code here every time someone comes up with their own special way of handing this?

I'm not sure I 100% understand the intention here - is it that we'd split the platform-specific code into entirely new drivers, and have those call into dw_i3c_probe() (presumably doing a bit of custom init either before or after that call)?

If so: I think the platform support should stay fairly minimal, so I'm not sure that warrants a new driver for each instance. In the ast2600 case it's just a couple of extra reg writes in the i3c init path. I'd be reluctant to split that out completely at this stage - but if this does grow, we can certainly reconsider.

Also, I'd like to allow for the case where the platform-specific parts may access the fields of struct dw_i3c_master; with this approach we don't need to expose that struct outside of the single driver.

Cheers,

Jeremy

author maintainer
#7 lore raw

PATCH 3/4 i3c: dw: Add AST2600 platform ops

In reply to Jeremy Kerr

Now that we have platform-specific hooks for the dw i3c driver, add platform support for the ASPEED AST2600 SoC.

The AST2600 has a small set of "i3c global" registers, providing platform-level i3c configuration outside of the i3c core.

For the ast2600, we need a couple of extra setup operations:

- on probe: find the i3c global register set and parse the SDA pullup resistor values

- on init: set the pullups accordingly, and set the i3c instance IDs

---
 drivers/i3c/master/dw-i3c-master.c | 122 +++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)
drivers/i3c/master/dw-i3c-master.c +122 -0
index 49b891449222..9be3348cba0e 100644
@@ -16,8 +16,10 @@
 #include <linux/iopoll.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
 
@@ -201,6 +203,28 @@
 
 #define XFER_TIMEOUT (msecs_to_jiffies(1000))
 
+/* AST2600-specific global register set */
+#define AST2600_I3CG_REG0(idx)	(((idx) * 4 * 4) + 0x10)
+#define AST2600_I3CG_REG1(idx)	(((idx) * 4 * 4) + 0x14)
+
+#define AST2600_I3CG_REG0_SDA_PULLUP_EN_MASK	GENMASK(29, 28)
+#define AST2600_I3CG_REG0_SDA_PULLUP_EN_2K	(0x0 << 28)
+#define AST2600_I3CG_REG0_SDA_PULLUP_EN_750	(0x2 << 28)
+
+#define AST2600_I3CG_REG1_I2C_MODE		BIT(0)
+#define AST2600_I3CG_REG1_TEST_MODE		BIT(1)
+#define AST2600_I3CG_REG1_ACT_MODE_MASK		GENMASK(3, 2)
+#define AST2600_I3CG_REG1_ACT_MODE(x)		(((x) << 2) & AST2600_I3CG_REG1_ACT_MODE_MASK)
+#define AST2600_I3CG_REG1_PENDING_INT_MASK	GENMASK(7, 4)
+#define AST2600_I3CG_REG1_PENDING_INT(x)	(((x) << 4) & AST2600_I3CG_REG1_PENDING_INT_MASK)
+#define AST2600_I3CG_REG1_SA_MASK		GENMASK(14, 8)
+#define AST2600_I3CG_REG1_SA(x)			(((x) << 8) & AST2600_I3CG_REG1_SA_MASK)
+#define AST2600_I3CG_REG1_SA_EN			BIT(15)
+#define AST2600_I3CG_REG1_INST_ID_MASK		GENMASK(19, 16)
+#define AST2600_I3CG_REG1_INST_ID(x)		(((x) << 16) & AST2600_I3CG_REG1_INST_ID_MASK)
+
+#define AST2600_DEFAULT_SDA_PULLUP_OHMS		2000
+
 struct dw_i3c_master_caps {
 	u8 cmdfifodepth;
 	u8 datafifodepth;
@@ -224,6 +248,12 @@ struct dw_i3c_xfer {
 	struct dw_i3c_cmd cmds[];
 };
 
+struct pdata_ast2600 {
+	struct regmap *global_regs;
+	unsigned int global_idx;
+	unsigned int sda_pullup;
+};
+
 struct dw_i3c_master {
 	struct i3c_master_controller base;
 	u16 maxdevs;
@@ -245,6 +275,7 @@ struct dw_i3c_master {
 	/* platform-specific data */
 	const struct dw_i3c_platform_ops *platform_ops;
 	union {
+		struct pdata_ast2600 ast2600;
 	} pdata;
 
 };
@@ -1145,6 +1176,97 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
 	.i2c_xfers = dw_i3c_master_i2c_xfers,
 };
 
+/* hardware-specific ops */
+
+static int ast2600_i3c_pullup_to_reg(unsigned int ohms, u32 *regp)
+{
+	u32 reg;
+
+	switch (ohms) {
+	case 2000:
+		reg = AST2600_I3CG_REG0_SDA_PULLUP_EN_2K;
+		break;
+	case 750:
+		reg = AST2600_I3CG_REG0_SDA_PULLUP_EN_750;
+		break;
+	case 545:
+		reg = AST2600_I3CG_REG0_SDA_PULLUP_EN_2K |
+			AST2600_I3CG_REG0_SDA_PULLUP_EN_750;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (regp)
+		*regp = reg;
+
+	return 0;
+}
+
+static int ast2600_i3c_probe(struct dw_i3c_master *master,
+			     struct platform_device *pdev)
+{
+	struct pdata_ast2600 *pdata = &master->pdata.ast2600;
+	struct device_node *np = pdev->dev.of_node;
+	struct of_phandle_args gspec;
+	int rc;
+
+	rc = of_parse_phandle_with_fixed_args(np, "aspeed,global-regs", 1, 0,
+					      &gspec);
+	if (rc)
+		return -ENODEV;
+
+	pdata->global_regs = syscon_node_to_regmap(gspec.np);
+	of_node_put(gspec.np);
+
+	if (IS_ERR(pdata->global_regs))
+		return PTR_ERR(pdata->global_regs);
+
+	pdata->global_idx = gspec.args[0];
+
+	rc = of_property_read_u32(np, "sda-pullup-ohms", &pdata->sda_pullup);
+	if (rc)
+		pdata->sda_pullup = AST2600_DEFAULT_SDA_PULLUP_OHMS;
+
+	rc = ast2600_i3c_pullup_to_reg(pdata->sda_pullup, NULL);
+	if (rc)
+		dev_err(&master->base.dev, "invalid sda-pullup value %d\n",
+			pdata->sda_pullup);
+
+	return rc;
+}
+
+static int ast2600_i3c_init(struct dw_i3c_master *master)
+{
+	struct pdata_ast2600 *pdata = &master->pdata.ast2600;
+	u32 reg = 0;
+	int rc;
+
+	/* reg0: set SDA pullup values */
+	rc = ast2600_i3c_pullup_to_reg(pdata->sda_pullup, &reg);
+	if (rc)
+		return rc;
+
+	rc = regmap_write(pdata->global_regs,
+			  AST2600_I3CG_REG0(pdata->global_idx), reg);
+	if (rc)
+		return rc;
+
+	/* reg1: set up the instance id, but leave everything else disabled,
+	 * as it's all for client mode
+	 */
+	reg = AST2600_I3CG_REG1_INST_ID(pdata->global_idx);
+	rc = regmap_write(pdata->global_regs,
+			  AST2600_I3CG_REG1(pdata->global_idx), reg);
+
+	return rc;
+}
+
+static const struct dw_i3c_platform_ops ast2600_platform_ops = {
+	.probe = ast2600_i3c_probe,
+	.init = ast2600_i3c_init,
+};
+
 static const struct of_device_id dw_i3c_master_of_match[] = {
 	{ .compatible = "snps,dw-i3c-master-1.00a", },
 	{},
Signature · 1 line
2.39.1
author maintainer
#8 lore raw

PATCH 4/4 i3c: dw: Add compatible string for ASPEED AST2600 BMC platform

In reply to Jeremy Kerr

Now that we have platform-specific code for the ast2600, enable it through a new compatible string.

---
 drivers/i3c/master/dw-i3c-master.c | 1 +
 1 file changed, 1 insertion(+)
drivers/i3c/master/dw-i3c-master.c +1 -0
index 9be3348cba0e..5ac226e0c558 100644
@@ -1269,6 +1269,7 @@ static const struct dw_i3c_platform_ops ast2600_platform_ops = {
 
 static const struct of_device_id dw_i3c_master_of_match[] = {
 	{ .compatible = "snps,dw-i3c-master-1.00a", },
+	{ .compatible = "aspeed,ast2600-i3c", .data = &ast2600_platform_ops },
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
Signature · 1 line
2.39.1
maintainer
#9 lore raw

cover i3c: Add support for ast2600 i3c controller

In reply to Jeremy Kerr
Quoted 16 lines · Jeremy Kerr

The AST2600 SoC hardware includes a set of i3c controllers, based on the designware i3c core, plus some global registers for SoC integration.

This series adds support for these i3c controllers, through the existing dw i3c master controller driver, by adding a set of platform-specific hooks to handle the global register configuration. This also gives us a way to add any future hardware-specific behaviours.

We also need a DT binding to describe the ast2600-specific hardware. Since this involves new (mandatory) properties, I have added this as a separate binding rather than add a new compat string to the dw binding.

The dt-binding example depends on a prior submission to the dt binding headers:

Quoted 7 lines

https://lore.kernel.org/linux-devicetree/cover.1676294433.git.jk at codeconstruct.com.au/

Full support for the global regmap will land with this queued mfd change:

https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git/commit/?id=cf2271843de835839e91c5c036492a87085af756

Of course, any queries/comments/etc are most welcome.

Quoted 20 lines

Cheers,

Jeremy

Jeremy Kerr (4):
dt-bindings: i3c: Add AST2600 i3c controller
i3c: dw: Add platform operations
i3c: dw: Add AST2600 platform ops
i3c: dw: Add compatible string for ASPEED AST2600 BMC platform

 .../bindings/i3c/aspeed,ast2600-i3c.yaml      |  73 ++++++++
 drivers/i3c/master/dw-i3c-master.c            | 165 +++++++++++++++++-
 2 files changed, 232 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml

--
2.39.1