22
22
#include <linux/slab.h>
23
23
#include <linux/spinlock.h>
24
24
#include <linux/workqueue.h>
25
+ #include <linux/of_device.h>
25
26
26
27
#define DEV_ID 0x0
27
28
#define DEV_ID_I3C_MASTER 0x5034
60
61
#define CTRL_HALT_EN BIT(30)
61
62
#define CTRL_MCS BIT(29)
62
63
#define CTRL_MCS_EN BIT(28)
64
+ #define CTRL_THD_DELAY (x ) (((x) << 24) & GENMASK(25, 24))
63
65
#define CTRL_HJ_DISEC BIT(8)
64
66
#define CTRL_MST_ACK BIT(7)
65
67
#define CTRL_HJ_ACK BIT(6)
70
72
#define CTRL_MIXED_FAST_BUS_MODE 2
71
73
#define CTRL_MIXED_SLOW_BUS_MODE 3
72
74
#define CTRL_BUS_MODE_MASK GENMASK(1, 0)
75
+ #define THD_DELAY_MAX 3
73
76
74
77
#define PRESCL_CTRL0 0x14
75
78
#define PRESCL_CTRL0_I2C (x ) ((x) << 16)
@@ -388,6 +391,10 @@ struct cdns_i3c_xfer {
388
391
struct cdns_i3c_cmd cmds [0 ];
389
392
};
390
393
394
+ struct cdns_i3c_data {
395
+ u8 thd_delay_ns ;
396
+ };
397
+
391
398
struct cdns_i3c_master {
392
399
struct work_struct hj_work ;
393
400
struct i3c_master_controller base ;
@@ -408,6 +415,7 @@ struct cdns_i3c_master {
408
415
struct clk * pclk ;
409
416
struct cdns_i3c_master_caps caps ;
410
417
unsigned long i3c_scl_lim ;
418
+ const struct cdns_i3c_data * devdata ;
411
419
};
412
420
413
421
static inline struct cdns_i3c_master *
@@ -1181,6 +1189,20 @@ static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
1181
1189
return 0 ;
1182
1190
}
1183
1191
1192
+ static u8 cdns_i3c_master_calculate_thd_delay (struct cdns_i3c_master * master )
1193
+ {
1194
+ unsigned long sysclk_rate = clk_get_rate (master -> sysclk );
1195
+ u8 thd_delay = DIV_ROUND_UP (master -> devdata -> thd_delay_ns ,
1196
+ (NSEC_PER_SEC / sysclk_rate ));
1197
+
1198
+ /* Every value greater than 3 is not valid. */
1199
+ if (thd_delay > THD_DELAY_MAX )
1200
+ thd_delay = THD_DELAY_MAX ;
1201
+
1202
+ /* CTLR_THD_DEL value is encoded. */
1203
+ return (THD_DELAY_MAX - thd_delay );
1204
+ }
1205
+
1184
1206
static int cdns_i3c_master_bus_init (struct i3c_master_controller * m )
1185
1207
{
1186
1208
struct cdns_i3c_master * master = to_cdns_i3c_master (m );
@@ -1264,6 +1286,15 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
1264
1286
* We will issue ENTDAA afterwards from the threaded IRQ handler.
1265
1287
*/
1266
1288
ctrl |= CTRL_HJ_ACK | CTRL_HJ_DISEC | CTRL_HALT_EN | CTRL_MCS_EN ;
1289
+
1290
+ /*
1291
+ * Configure data hold delay based on device-specific data.
1292
+ *
1293
+ * MIPI I3C Specification 1.0 defines non-zero minimal tHD_PP timing on
1294
+ * master output. This setting allows to meet this timing on master's
1295
+ * SoC outputs, regardless of PCB balancing.
1296
+ */
1297
+ ctrl |= CTRL_THD_DELAY (cdns_i3c_master_calculate_thd_delay (master ));
1267
1298
writel (ctrl , master -> regs + CTRL );
1268
1299
1269
1300
cdns_i3c_master_enable (master );
@@ -1521,6 +1552,15 @@ static void cdns_i3c_master_hj(struct work_struct *work)
1521
1552
i3c_master_do_daa (& master -> base );
1522
1553
}
1523
1554
1555
+ static struct cdns_i3c_data cdns_i3c_devdata = {
1556
+ .thd_delay_ns = 10 ,
1557
+ };
1558
+
1559
+ static const struct of_device_id cdns_i3c_master_of_ids [] = {
1560
+ { .compatible = "cdns,i3c-master" , .data = & cdns_i3c_devdata },
1561
+ { /* sentinel */ },
1562
+ };
1563
+
1524
1564
static int cdns_i3c_master_probe (struct platform_device * pdev )
1525
1565
{
1526
1566
struct cdns_i3c_master * master ;
@@ -1532,6 +1572,10 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
1532
1572
if (!master )
1533
1573
return - ENOMEM ;
1534
1574
1575
+ master -> devdata = of_device_get_match_data (& pdev -> dev );
1576
+ if (!master -> devdata )
1577
+ return - EINVAL ;
1578
+
1535
1579
res = platform_get_resource (pdev , IORESOURCE_MEM , 0 );
1536
1580
master -> regs = devm_ioremap_resource (& pdev -> dev , res );
1537
1581
if (IS_ERR (master -> regs ))
@@ -1631,11 +1675,6 @@ static int cdns_i3c_master_remove(struct platform_device *pdev)
1631
1675
return 0 ;
1632
1676
}
1633
1677
1634
- static const struct of_device_id cdns_i3c_master_of_ids [] = {
1635
- { .compatible = "cdns,i3c-master" },
1636
- { /* sentinel */ },
1637
- };
1638
-
1639
1678
static struct platform_driver cdns_i3c_master = {
1640
1679
.probe = cdns_i3c_master_probe ,
1641
1680
.remove = cdns_i3c_master_remove ,
0 commit comments