Skip to content

Commit d782188

Browse files
jk-ozlabsalexandrebelloni
authored andcommitted
i3c: dw: Add infrastructure for platform-specific implementations
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 some infrastructure to allow platform-specific behaviour: common probe/remove functions, a set of platform hook operations, and a pointer for platform-specific data in struct dw_i3c_master. Move the common api into a new (i3c local) header file. Platforms will provide their own struct platform_driver, which allocates struct dw_i3c_master, does any platform-specific probe behaviour, and calls into the common probe. A future change will add new platform support that uses this infrastructure. Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au> Reviewed-by: Joel Stanley <joel@jms.id.au> Link: https://lore.kernel.org/r/20230331091501.3800299-2-jk@codeconstruct.com.au Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent 66b32e3 commit d782188

2 files changed

Lines changed: 97 additions & 34 deletions

File tree

drivers/i3c/master/dw-i3c-master.c

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <linux/reset.h>
2222
#include <linux/slab.h>
2323

24+
#include "dw-i3c-master.h"
25+
2426
#define DEVICE_CTRL 0x0
2527
#define DEV_CTRL_ENABLE BIT(31)
2628
#define DEV_CTRL_RESUME BIT(30)
@@ -189,8 +191,6 @@
189191
#define DEV_ADDR_TABLE_STATIC_ADDR(x) ((x) & GENMASK(6, 0))
190192
#define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2))
191193

192-
#define MAX_DEVS 32
193-
194194
#define I3C_BUS_SDR1_SCL_RATE 8000000
195195
#define I3C_BUS_SDR2_SCL_RATE 6000000
196196
#define I3C_BUS_SDR3_SCL_RATE 4000000
@@ -201,11 +201,6 @@
201201

202202
#define XFER_TIMEOUT (msecs_to_jiffies(1000))
203203

204-
struct dw_i3c_master_caps {
205-
u8 cmdfifodepth;
206-
u8 datafifodepth;
207-
};
208-
209204
struct dw_i3c_cmd {
210205
u32 cmd_lo;
211206
u32 cmd_hi;
@@ -224,25 +219,6 @@ struct dw_i3c_xfer {
224219
struct dw_i3c_cmd cmds[];
225220
};
226221

227-
struct dw_i3c_master {
228-
struct i3c_master_controller base;
229-
u16 maxdevs;
230-
u16 datstartaddr;
231-
u32 free_pos;
232-
struct {
233-
struct list_head list;
234-
struct dw_i3c_xfer *cur;
235-
spinlock_t lock;
236-
} xferqueue;
237-
struct dw_i3c_master_caps caps;
238-
void __iomem *regs;
239-
struct reset_control *core_rst;
240-
struct clk *core_clk;
241-
char version[5];
242-
char type[5];
243-
u8 addrs[MAX_DEVS];
244-
};
245-
246222
struct dw_i3c_i2c_dev_data {
247223
u8 index;
248224
};
@@ -602,6 +578,10 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
602578
u32 thld_ctrl;
603579
int ret;
604580

581+
ret = master->platform_ops->init(master);
582+
if (ret)
583+
return ret;
584+
605585
switch (bus->mode) {
606586
case I3C_BUS_MODE_MIXED_FAST:
607587
case I3C_BUS_MODE_MIXED_LIMITED:
@@ -1124,14 +1104,23 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
11241104
.i2c_xfers = dw_i3c_master_i2c_xfers,
11251105
};
11261106

1127-
static int dw_i3c_probe(struct platform_device *pdev)
1107+
/* default platform ops implementations */
1108+
static int dw_i3c_platform_init_nop(struct dw_i3c_master *i3c)
1109+
{
1110+
return 0;
1111+
}
1112+
1113+
static const struct dw_i3c_platform_ops dw_i3c_platform_ops_default = {
1114+
.init = dw_i3c_platform_init_nop,
1115+
};
1116+
1117+
int dw_i3c_common_probe(struct dw_i3c_master *master,
1118+
struct platform_device *pdev)
11281119
{
1129-
struct dw_i3c_master *master;
11301120
int ret, irq;
11311121

1132-
master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
1133-
if (!master)
1134-
return -ENOMEM;
1122+
if (!master->platform_ops)
1123+
master->platform_ops = &dw_i3c_platform_ops_default;
11351124

11361125
master->regs = devm_platform_ioremap_resource(pdev, 0);
11371126
if (IS_ERR(master->regs))
@@ -1192,17 +1181,37 @@ static int dw_i3c_probe(struct platform_device *pdev)
11921181

11931182
return ret;
11941183
}
1184+
EXPORT_SYMBOL_GPL(dw_i3c_common_probe);
11951185

1196-
static void dw_i3c_remove(struct platform_device *pdev)
1186+
void dw_i3c_common_remove(struct dw_i3c_master *master)
11971187
{
1198-
struct dw_i3c_master *master = platform_get_drvdata(pdev);
1199-
12001188
i3c_master_unregister(&master->base);
12011189

12021190
reset_control_assert(master->core_rst);
12031191

12041192
clk_disable_unprepare(master->core_clk);
12051193
}
1194+
EXPORT_SYMBOL_GPL(dw_i3c_common_remove);
1195+
1196+
/* base platform implementation */
1197+
1198+
static int dw_i3c_probe(struct platform_device *pdev)
1199+
{
1200+
struct dw_i3c_master *master;
1201+
1202+
master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
1203+
if (!master)
1204+
return -ENOMEM;
1205+
1206+
return dw_i3c_common_probe(master, pdev);
1207+
}
1208+
1209+
static void dw_i3c_remove(struct platform_device *pdev)
1210+
{
1211+
struct dw_i3c_master *master = platform_get_drvdata(pdev);
1212+
1213+
dw_i3c_common_remove(master);
1214+
}
12061215

12071216
static const struct of_device_id dw_i3c_master_of_match[] = {
12081217
{ .compatible = "snps,dw-i3c-master-1.00a", },

drivers/i3c/master/dw-i3c-master.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (c) 2023 Code Construct
4+
*
5+
* Author: Jeremy Kerr <jk@codeconstruct.com.au>
6+
*/
7+
8+
#include <linux/clk.h>
9+
#include <linux/i3c/master.h>
10+
#include <linux/reset.h>
11+
#include <linux/types.h>
12+
13+
#define DW_I3C_MAX_DEVS 32
14+
15+
struct dw_i3c_master_caps {
16+
u8 cmdfifodepth;
17+
u8 datafifodepth;
18+
};
19+
20+
struct dw_i3c_master {
21+
struct i3c_master_controller base;
22+
u16 maxdevs;
23+
u16 datstartaddr;
24+
u32 free_pos;
25+
struct {
26+
struct list_head list;
27+
struct dw_i3c_xfer *cur;
28+
spinlock_t lock;
29+
} xferqueue;
30+
struct dw_i3c_master_caps caps;
31+
void __iomem *regs;
32+
struct reset_control *core_rst;
33+
struct clk *core_clk;
34+
char version[5];
35+
char type[5];
36+
u8 addrs[DW_I3C_MAX_DEVS];
37+
38+
/* platform-specific data */
39+
const struct dw_i3c_platform_ops *platform_ops;
40+
};
41+
42+
struct dw_i3c_platform_ops {
43+
/*
44+
* Called on early bus init: the i3c has been set up, but before any
45+
* transactions have taken place. Platform implementations may use to
46+
* perform actual device enabling with the i3c core ready.
47+
*/
48+
int (*init)(struct dw_i3c_master *i3c);
49+
};
50+
51+
extern int dw_i3c_common_probe(struct dw_i3c_master *master,
52+
struct platform_device *pdev);
53+
extern void dw_i3c_common_remove(struct dw_i3c_master *master);
54+

0 commit comments

Comments
 (0)