@@ -182,6 +182,7 @@ struct svc_i3c_regs_save {
182
182
* @ibi.lock: IBI lock
183
183
* @lock: Transfer lock, protect between IBI work thread and callbacks from master
184
184
* @enabled_events: Bit masks for enable events (IBI, HotJoin).
185
+ * @mctrl_config: Configuration value in SVC_I3C_MCTRL for setting speed back.
185
186
*/
186
187
struct svc_i3c_master {
187
188
struct i3c_master_controller base ;
@@ -212,6 +213,7 @@ struct svc_i3c_master {
212
213
} ibi ;
213
214
struct mutex lock ;
214
215
int enabled_events ;
216
+ u32 mctrl_config ;
215
217
};
216
218
217
219
/**
@@ -529,6 +531,54 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
529
531
return IRQ_HANDLED ;
530
532
}
531
533
534
+ static int svc_i3c_master_set_speed (struct i3c_master_controller * m ,
535
+ enum i3c_open_drain_speed speed )
536
+ {
537
+ struct svc_i3c_master * master = to_svc_i3c_master (m );
538
+ struct i3c_bus * bus = i3c_master_get_bus (& master -> base );
539
+ u32 ppbaud , odbaud , odhpp , mconfig ;
540
+ unsigned long fclk_rate ;
541
+ int ret ;
542
+
543
+ ret = pm_runtime_resume_and_get (master -> dev );
544
+ if (ret < 0 ) {
545
+ dev_err (master -> dev , "<%s> Cannot get runtime PM.\n" , __func__ );
546
+ return ret ;
547
+ }
548
+
549
+ switch (speed ) {
550
+ case I3C_OPEN_DRAIN_SLOW_SPEED :
551
+ fclk_rate = clk_get_rate (master -> fclk );
552
+ if (!fclk_rate ) {
553
+ ret = - EINVAL ;
554
+ goto rpm_out ;
555
+ }
556
+ /*
557
+ * Set 50% duty-cycle I2C speed to I3C OPEN-DRAIN mode, so the first
558
+ * broadcast address is visible to all I2C/I3C devices on the I3C bus.
559
+ * I3C device working as a I2C device will turn off its 50ns Spike
560
+ * Filter to change to I3C mode.
561
+ */
562
+ mconfig = master -> mctrl_config ;
563
+ ppbaud = FIELD_GET (GENMASK (11 , 8 ), mconfig );
564
+ odhpp = 0 ;
565
+ odbaud = DIV_ROUND_UP (fclk_rate , bus -> scl_rate .i2c * (2 + 2 * ppbaud )) - 1 ;
566
+ mconfig &= ~GENMASK (24 , 16 );
567
+ mconfig |= SVC_I3C_MCONFIG_ODBAUD (odbaud ) | SVC_I3C_MCONFIG_ODHPP (odhpp );
568
+ writel (mconfig , master -> regs + SVC_I3C_MCONFIG );
569
+ break ;
570
+ case I3C_OPEN_DRAIN_NORMAL_SPEED :
571
+ writel (master -> mctrl_config , master -> regs + SVC_I3C_MCONFIG );
572
+ break ;
573
+ }
574
+
575
+ rpm_out :
576
+ pm_runtime_mark_last_busy (master -> dev );
577
+ pm_runtime_put_autosuspend (master -> dev );
578
+
579
+ return ret ;
580
+ }
581
+
532
582
static int svc_i3c_master_bus_init (struct i3c_master_controller * m )
533
583
{
534
584
struct svc_i3c_master * master = to_svc_i3c_master (m );
@@ -611,6 +661,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
611
661
SVC_I3C_MCONFIG_I2CBAUD (i2cbaud );
612
662
writel (reg , master -> regs + SVC_I3C_MCONFIG );
613
663
664
+ master -> mctrl_config = reg ;
614
665
/* Master core's registration */
615
666
ret = i3c_master_get_free_addr (m , 0 );
616
667
if (ret < 0 )
@@ -1645,6 +1696,7 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
1645
1696
.disable_ibi = svc_i3c_master_disable_ibi ,
1646
1697
.enable_hotjoin = svc_i3c_master_enable_hotjoin ,
1647
1698
.disable_hotjoin = svc_i3c_master_disable_hotjoin ,
1699
+ .set_speed = svc_i3c_master_set_speed ,
1648
1700
};
1649
1701
1650
1702
static int svc_i3c_master_prepare_clks (struct svc_i3c_master * master )
0 commit comments