Message ID | 20240806064851.2425797-1-carlos.song@nxp.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [1/2] i3c: master: support to adjust first broadcast address speed | expand |
On Tue, Aug 06, 2024 at 02:48:50PM +0800, carlos.song@nxp.com wrote: > From: Carlos Song <carlos.song@nxp.com> > > According to I3C spec 6.2 Timing Specification, the Open Drain High Period > of SCL Clock timing for first broadcast address should be adjusted to 200ns > at least. I3C device working as i2c device will see the broadcast to close > its Spike Filter then change to work at I3C mode. After that I3C open drain > SCL high level should be adjusted back. > > Signed-off-by: Carlos Song <carlos.song@nxp.com> A small comments below Reviewed-by: Frank Li <Frank.Li@nxp.com> > --- > drivers/i3c/master.c | 12 ++++++++++++ > include/linux/i3c/master.h | 16 ++++++++++++++++ > 2 files changed, 28 insertions(+) > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > index 7028f03c2c42..6f3eb710a75d 100644 > --- a/drivers/i3c/master.c > +++ b/drivers/i3c/master.c > @@ -1868,6 +1868,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) > goto err_bus_cleanup; > } > > + if (master->ops->set_speed) { > + ret = master->ops->set_speed(master, I3C_OPEN_DRAIN_SLOW_SPEED); > + if (ret) > + goto err_bus_cleanup; > + } > + > /* > * Reset all dynamic address that may have been assigned before > * (assigned by the bootloader for example). > @@ -1876,6 +1882,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) > if (ret && ret != I3C_ERROR_M2) > goto err_bus_cleanup; > > + if (master->ops->set_speed) { > + master->ops->set_speed(master, I3C_OPEN_DRAIN_NORMAL_SPEED); > + if (ret) > + goto err_bus_cleanup; > + } > + > /* Disable all slave events before starting DAA. */ > ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, > I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | > diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h > index 074f632868d9..02e4f47f9d01 100644 > --- a/include/linux/i3c/master.h > +++ b/include/linux/i3c/master.h > @@ -277,6 +277,20 @@ enum i3c_bus_mode { > I3C_BUS_MODE_MIXED_SLOW, > }; > > +/** > + * enum i3c_open_drain_speed - I3C open drain speed > + * @I3C_OPEN_DRAIN_SLOW_SPEED: Slow open drain speed for First Broadcast Address. > + * First Broadcast Address in this speed is visible to all I2C/I3C > + * devices on the I3C bus. I3C device working as a I2C device will > + * turn off its 50ns Spike Filter to change to work in I3C mode. > + * @I3C_OPEN_DRAIN_NORMAL_SPEED: Normal open drain speed configured according to > + * I3C bus mode. > + */ > +enum i3c_open_drain_speed { > + I3C_OPEN_DRAIN_SLOW_SPEED, > + I3C_OPEN_DRAIN_NORMAL_SPEED, > +}; > + > /** > * enum i3c_addr_slot_status - I3C address slot status > * @I3C_ADDR_SLOT_FREE: address is free > @@ -436,6 +450,7 @@ struct i3c_bus { > * NULL. > * @enable_hotjoin: enable hot join event detect. > * @disable_hotjoin: disable hot join event detect. > + * @set_speed: adjust I3C open drain mode timing. adjust I3C bus speed, which is generally used for reduced the speed for first broardcast address. > */ > struct i3c_master_controller_ops { > int (*bus_init)(struct i3c_master_controller *master); > @@ -464,6 +479,7 @@ struct i3c_master_controller_ops { > struct i3c_ibi_slot *slot); > int (*enable_hotjoin)(struct i3c_master_controller *master); > int (*disable_hotjoin)(struct i3c_master_controller *master); > + int (*set_speed)(struct i3c_master_controller *master, enum i3c_open_drain_speed speed); > }; > > /** > -- > 2.34.1 >
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 7028f03c2c42..6f3eb710a75d 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1868,6 +1868,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) goto err_bus_cleanup; } + if (master->ops->set_speed) { + ret = master->ops->set_speed(master, I3C_OPEN_DRAIN_SLOW_SPEED); + if (ret) + goto err_bus_cleanup; + } + /* * Reset all dynamic address that may have been assigned before * (assigned by the bootloader for example). @@ -1876,6 +1882,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) if (ret && ret != I3C_ERROR_M2) goto err_bus_cleanup; + if (master->ops->set_speed) { + master->ops->set_speed(master, I3C_OPEN_DRAIN_NORMAL_SPEED); + if (ret) + goto err_bus_cleanup; + } + /* Disable all slave events before starting DAA. */ ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index 074f632868d9..02e4f47f9d01 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -277,6 +277,20 @@ enum i3c_bus_mode { I3C_BUS_MODE_MIXED_SLOW, }; +/** + * enum i3c_open_drain_speed - I3C open drain speed + * @I3C_OPEN_DRAIN_SLOW_SPEED: Slow open drain speed for First Broadcast Address. + * First Broadcast Address in this speed is visible to all I2C/I3C + * devices on the I3C bus. I3C device working as a I2C device will + * turn off its 50ns Spike Filter to change to work in I3C mode. + * @I3C_OPEN_DRAIN_NORMAL_SPEED: Normal open drain speed configured according to + * I3C bus mode. + */ +enum i3c_open_drain_speed { + I3C_OPEN_DRAIN_SLOW_SPEED, + I3C_OPEN_DRAIN_NORMAL_SPEED, +}; + /** * enum i3c_addr_slot_status - I3C address slot status * @I3C_ADDR_SLOT_FREE: address is free @@ -436,6 +450,7 @@ struct i3c_bus { * NULL. * @enable_hotjoin: enable hot join event detect. * @disable_hotjoin: disable hot join event detect. + * @set_speed: adjust I3C open drain mode timing. */ struct i3c_master_controller_ops { int (*bus_init)(struct i3c_master_controller *master); @@ -464,6 +479,7 @@ struct i3c_master_controller_ops { struct i3c_ibi_slot *slot); int (*enable_hotjoin)(struct i3c_master_controller *master); int (*disable_hotjoin)(struct i3c_master_controller *master); + int (*set_speed)(struct i3c_master_controller *master, enum i3c_open_drain_speed speed); }; /**