Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0398fb70 authored by Joakim Tjernlund's avatar Joakim Tjernlund Committed by Grant Likely
Browse files

spi/spi_mpc8xxx: Fix QE mode Litte Endian



QE mode uses Little Endian so words > 8 bits are byte swapped.
Workaround this by always enforcing wordsize 8 for words
> 8 bits. Unfortunately this will not work for LSB transfers
where wordsize is > 8 bits so disable these for now.

Also move the different quirks into its own function to keep
mpc8xxx_spi_setup_transfer() sane.

Signed-off-by: default avatarJoakim Tjernlund <Joakim.Tjernlund@transmode.se>
Acked-by: default avatarAnton Vorontsov <cbouatmailru@gmail.com>
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent f9218c2a
Loading
Loading
Loading
Loading
+70 −31
Original line number Diff line number Diff line
@@ -286,36 +286,12 @@ static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
	}
}

static
int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static int
mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
			   struct spi_device *spi,
			   struct mpc8xxx_spi *mpc8xxx_spi,
			   int bits_per_word)
{
	struct mpc8xxx_spi *mpc8xxx_spi;
	u8 bits_per_word, pm;
	u32 hz;
	struct spi_mpc8xxx_cs	*cs = spi->controller_state;

	mpc8xxx_spi = spi_master_get_devdata(spi->master);

	if (t) {
		bits_per_word = t->bits_per_word;
		hz = t->speed_hz;
	} else {
		bits_per_word = 0;
		hz = 0;
	}

	/* spi_transfer level calls that work per-word */
	if (!bits_per_word)
		bits_per_word = spi->bits_per_word;

	/* Make sure its a bit width we support [4..16, 32] */
	if ((bits_per_word < 4)
	    || ((bits_per_word > 16) && (bits_per_word != 32)))
		return -EINVAL;

	if (!hz)
		hz = spi->max_speed_hz;

	cs->rx_shift = 0;
	cs->tx_shift = 0;
	if (bits_per_word <= 8) {
@@ -346,12 +322,75 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
		else
			cs->rx_shift = 0;
	}

	mpc8xxx_spi->rx_shift = cs->rx_shift;
	mpc8xxx_spi->tx_shift = cs->tx_shift;
	mpc8xxx_spi->get_rx = cs->get_rx;
	mpc8xxx_spi->get_tx = cs->get_tx;

	return bits_per_word;
}

static int
mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
			  struct spi_device *spi,
			  int bits_per_word)
{
	/* QE uses Little Endian for words > 8
	 * so transform all words > 8 into 8 bits
	 * Unfortnatly that doesn't work for LSB so
	 * reject these for now */
	/* Note: 32 bits word, LSB works iff
	 * tfcr/rfcr is set to CPMFCR_GBL */
	if (spi->mode & SPI_LSB_FIRST &&
	    bits_per_word > 8)
		return -EINVAL;
	if (bits_per_word > 8)
		return 8; /* pretend its 8 bits */
	return bits_per_word;
}

static
int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
	struct mpc8xxx_spi *mpc8xxx_spi;
	int bits_per_word;
	u8 pm;
	u32 hz;
	struct spi_mpc8xxx_cs	*cs = spi->controller_state;

	mpc8xxx_spi = spi_master_get_devdata(spi->master);

	if (t) {
		bits_per_word = t->bits_per_word;
		hz = t->speed_hz;
	} else {
		bits_per_word = 0;
		hz = 0;
	}

	/* spi_transfer level calls that work per-word */
	if (!bits_per_word)
		bits_per_word = spi->bits_per_word;

	/* Make sure its a bit width we support [4..16, 32] */
	if ((bits_per_word < 4)
	    || ((bits_per_word > 16) && (bits_per_word != 32)))
		return -EINVAL;

	if (!hz)
		hz = spi->max_speed_hz;

	if (!(mpc8xxx_spi->flags & SPI_CPM_MODE))
		bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi,
							   mpc8xxx_spi,
							   bits_per_word);
	else if (mpc8xxx_spi->flags & SPI_QE)
		bits_per_word = mspi_apply_qe_mode_quirks(cs, spi,
							  bits_per_word);

	if (bits_per_word < 0)
		return bits_per_word;

	if (bits_per_word == 32)
		bits_per_word = 0;
	else