@@ -182,6 +182,7 @@ struct svc_i3c_regs_save {
182182 * @ibi.lock: IBI lock
183183 * @lock: Transfer lock, protect between IBI work thread and callbacks from master
184184 * @enabled_events: Bit masks for enable events (IBI, HotJoin).
185+ * @mctrl_config: Configuration value in SVC_I3C_MCTRL for setting speed back.
185186 */
186187struct svc_i3c_master {
187188 struct i3c_master_controller base ;
@@ -212,6 +213,7 @@ struct svc_i3c_master {
212213 } ibi ;
213214 struct mutex lock ;
214215 int enabled_events ;
216+ u32 mctrl_config ;
215217};
216218
217219/**
@@ -529,6 +531,54 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
529531 return IRQ_HANDLED ;
530532}
531533
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+
532582static int svc_i3c_master_bus_init (struct i3c_master_controller * m )
533583{
534584 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)
611661 SVC_I3C_MCONFIG_I2CBAUD (i2cbaud );
612662 writel (reg , master -> regs + SVC_I3C_MCONFIG );
613663
664+ master -> mctrl_config = reg ;
614665 /* Master core's registration */
615666 ret = i3c_master_get_free_addr (m , 0 );
616667 if (ret < 0 )
@@ -1645,6 +1696,7 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
16451696 .disable_ibi = svc_i3c_master_disable_ibi ,
16461697 .enable_hotjoin = svc_i3c_master_enable_hotjoin ,
16471698 .disable_hotjoin = svc_i3c_master_disable_hotjoin ,
1699+ .set_speed = svc_i3c_master_set_speed ,
16481700};
16491701
16501702static int svc_i3c_master_prepare_clks (struct svc_i3c_master * master )
0 commit comments