twsi: some variants clear interrupt flag by writing 0, others by writing 1

Make that distinction more explicit and regular in the code.
The difference in behavior is documented in the respective datasheets.

Previously, the code handled the distinction by writing the control
register multiple times where at least one write was zero and another
was one.

This can be considered a follow-up to r363021.

Reviewed by:	manu
MFC after:	4 weeks
Differential Revision: https://reviews.freebsd.org/D26308
This commit is contained in:
Andriy Gapon 2020-09-07 06:32:03 +00:00
parent e21a4ccfd1
commit 6305020526
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=365397
3 changed files with 14 additions and 7 deletions

View File

@ -122,6 +122,10 @@ a10_twsi_attach(device_t dev)
sc->reg_soft_reset = TWI_SRST;
sc->need_ack = true;
if (ofw_bus_is_compatible(dev, "allwinner,sun6i-a31-i2c") ||
ofw_bus_is_compatible(dev, "allwinner,sun6i-a83t-i2c"))
sc->iflag_w1c = true;
return (twsi_attach(dev));
}

View File

@ -147,7 +147,11 @@ twsi_clear_iflg(struct twsi_softc *sc)
{
DELAY(1000);
twsi_control_clear(sc, TWSI_CONTROL_IFLG);
/* There are two ways of clearing IFLAG. */
if (sc->iflag_w1c)
twsi_control_set(sc, TWSI_CONTROL_IFLG);
else
twsi_control_clear(sc, TWSI_CONTROL_IFLG);
DELAY(1000);
}
@ -667,13 +671,11 @@ twsi_intr(void *arg)
}
debugf(sc->dev, "Refresh reg_control\n");
/*
* Fix silicon bug on > Allwinner A20 by doing a read and writing
* again to the control register
/*
* Newer Allwinner chips clear IFLG after writing 1 to it.
*/
status = TWSI_READ(sc, sc->reg_status);
TWSI_WRITE(sc, sc->reg_control,
sc->control_val | TWSI_CONTROL_IFLG);
TWSI_WRITE(sc, sc->reg_control, sc->control_val |
(sc->iflag_w1c ? TWSI_CONTROL_IFLG : 0));
debugf(sc->dev, "Done with interrupts\n\n");
if (transfer_done == 1) {

View File

@ -66,6 +66,7 @@ struct twsi_softc {
int error;
uint32_t control_val;
bool need_ack;
bool iflag_w1c;
bus_size_t reg_data;
bus_size_t reg_slave_addr;