Skip to content

Commit 635bf3c

Browse files
Akhil RAndi Shyti
authored andcommitted
i2c: tegra: Use internal reset when reset property is not available
For controllers that has an internal software reset, make the reset property optional. This provides and option to use I2C in systems that choose to restrict reset control from Linux or not to implement the ACPI _RST method. Internal reset was not required when the reset control was mandatory. But on platforms where the resets are outside the control of Linux, this had to be implemented by just returning success from BPMP or with an empty _RST method in the ACPI table, basically ignoring the reset. While the internal reset is not identical to the hard reset of the controller, this will reset all the internal state of the controller including FIFOs. This may slightly alter the behaviour in systems which were ignoring the reset but it should not cause any functional difference since all the required I2C registers are configured after this reset, just as in boot. Considering that this sequence is hit during the boot or during the I2C recovery path from an error, the internal reset provides a better alternative than just ignoring the reset. Signed-off-by: Akhil R <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Andi Shyti <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent ffdd205 commit 635bf3c

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

drivers/i2c/busses/i2c-tegra.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@
134134
#define I2C_MST_FIFO_STATUS_TX GENMASK(23, 16)
135135
#define I2C_MST_FIFO_STATUS_RX GENMASK(7, 0)
136136

137+
#define I2C_MASTER_RESET_CNTRL 0x0a8
138+
137139
/* configuration load timeout in microseconds */
138140
#define I2C_CONFIG_LOAD_TIMEOUT 1000000
139141

@@ -184,6 +186,9 @@ enum msg_end_type {
184186
* @has_mst_fifo: The I2C controller contains the new MST FIFO interface that
185187
* provides additional features and allows for longer messages to
186188
* be transferred in one go.
189+
* @has_mst_reset: The I2C controller contains MASTER_RESET_CTRL register which
190+
* provides an alternative to controller reset when configured as
191+
* I2C master
187192
* @quirks: I2C adapter quirks for limiting write/read transfer size and not
188193
* allowing 0 length transfers.
189194
* @supports_bus_clear: Bus Clear support to recover from bus hang during
@@ -213,6 +218,7 @@ struct tegra_i2c_hw_feature {
213218
bool has_multi_master_mode;
214219
bool has_slcg_override_reg;
215220
bool has_mst_fifo;
221+
bool has_mst_reset;
216222
const struct i2c_adapter_quirks *quirks;
217223
bool supports_bus_clear;
218224
bool has_apb_dma;
@@ -605,12 +611,42 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
605611
return 0;
606612
}
607613

614+
static int tegra_i2c_master_reset(struct tegra_i2c_dev *i2c_dev)
615+
{
616+
if (!i2c_dev->hw->has_mst_reset)
617+
return -EOPNOTSUPP;
618+
619+
/*
620+
* Writing 1 to I2C_MASTER_RESET_CNTRL will reset all internal state of
621+
* Master logic including FIFOs. Clear this bit to 0 for normal operation.
622+
* SW needs to wait for 2us after assertion and de-assertion of this soft
623+
* reset.
624+
*/
625+
i2c_writel(i2c_dev, 0x1, I2C_MASTER_RESET_CNTRL);
626+
fsleep(2);
627+
628+
i2c_writel(i2c_dev, 0x0, I2C_MASTER_RESET_CNTRL);
629+
fsleep(2);
630+
631+
return 0;
632+
}
633+
608634
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
609635
{
610636
u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode;
611637
struct i2c_timings *t = &i2c_dev->timings;
612638
int err;
613639

640+
/*
641+
* Reset the controller before initializing it.
642+
* In case if device_reset() returns -ENOENT, i.e. when the reset is
643+
* not available, the internal software reset will be used if it is
644+
* supported by the controller.
645+
*/
646+
err = device_reset(i2c_dev->dev);
647+
if (err == -ENOENT)
648+
err = tegra_i2c_master_reset(i2c_dev);
649+
614650
/*
615651
* The reset shouldn't ever fail in practice. The failure will be a
616652
* sign of a severe problem that needs to be resolved. Still we don't
@@ -619,7 +655,6 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
619655
* emit a noisy warning on error, which won't stay unnoticed and
620656
* won't hose machine entirely.
621657
*/
622-
err = device_reset(i2c_dev->dev);
623658
WARN_ON_ONCE(err);
624659

625660
if (IS_DVC(i2c_dev))
@@ -1468,6 +1503,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
14681503
.has_multi_master_mode = false,
14691504
.has_slcg_override_reg = false,
14701505
.has_mst_fifo = false,
1506+
.has_mst_reset = false,
14711507
.quirks = &tegra_i2c_quirks,
14721508
.supports_bus_clear = false,
14731509
.has_apb_dma = true,
@@ -1492,6 +1528,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
14921528
.has_multi_master_mode = false,
14931529
.has_slcg_override_reg = false,
14941530
.has_mst_fifo = false,
1531+
.has_mst_reset = false,
14951532
.quirks = &tegra_i2c_quirks,
14961533
.supports_bus_clear = false,
14971534
.has_apb_dma = true,
@@ -1516,6 +1553,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
15161553
.has_multi_master_mode = false,
15171554
.has_slcg_override_reg = false,
15181555
.has_mst_fifo = false,
1556+
.has_mst_reset = false,
15191557
.quirks = &tegra_i2c_quirks,
15201558
.supports_bus_clear = true,
15211559
.has_apb_dma = true,
@@ -1540,6 +1578,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
15401578
.has_multi_master_mode = false,
15411579
.has_slcg_override_reg = true,
15421580
.has_mst_fifo = false,
1581+
.has_mst_reset = false,
15431582
.quirks = &tegra_i2c_quirks,
15441583
.supports_bus_clear = true,
15451584
.has_apb_dma = true,
@@ -1564,6 +1603,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
15641603
.has_multi_master_mode = false,
15651604
.has_slcg_override_reg = true,
15661605
.has_mst_fifo = false,
1606+
.has_mst_reset = false,
15671607
.quirks = &tegra_i2c_quirks,
15681608
.supports_bus_clear = true,
15691609
.has_apb_dma = true,
@@ -1588,6 +1628,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
15881628
.has_multi_master_mode = false,
15891629
.has_slcg_override_reg = true,
15901630
.has_mst_fifo = false,
1631+
.has_mst_reset = false,
15911632
.quirks = &tegra_i2c_quirks,
15921633
.supports_bus_clear = true,
15931634
.has_apb_dma = false,
@@ -1612,6 +1653,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
16121653
.has_multi_master_mode = true,
16131654
.has_slcg_override_reg = true,
16141655
.has_mst_fifo = true,
1656+
.has_mst_reset = true,
16151657
.quirks = &tegra194_i2c_quirks,
16161658
.supports_bus_clear = true,
16171659
.has_apb_dma = false,

0 commit comments

Comments
 (0)