[RFC PATCH v1] spi: fsl_spi: Convert to transfer_one

From: Christophe Leroy
Date: Thu Aug 18 2022 - 09:39:35 EST


Let the core handle all the chipselect bakery and replace
transfer_one_message() by transfer_one() and prepare_message().

At the time being, there is fsl_spi_cs_control() to handle
chipselects. That function handles both GPIO and non-GPIO
chipselects. The GPIO chipselects will now be handled by
the core directly, so only handle non-GPIO chipselects and
hook it to ->set_cs

Signed-off-by: Christophe Leroy <christophe.leroy@xxxxxxxxxx>
---
Sending as an RFC as I'm not 100% sure of the correctness.
I successfully tested it on the hardware I have though.
Not sure about the change from m->is_dma_mapped to !!t->tx_dma || !!t->rx_dma
---
drivers/spi/spi-fsl-spi.c | 157 +++++++++++---------------------------
1 file changed, 43 insertions(+), 114 deletions(-)

diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index bdf94cc7be1a..731624f157fc 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -111,32 +111,6 @@ static void fsl_spi_change_mode(struct spi_device *spi)
local_irq_restore(flags);
}

-static void fsl_spi_chipselect(struct spi_device *spi, int value)
-{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
- struct fsl_spi_platform_data *pdata;
- struct spi_mpc8xxx_cs *cs = spi->controller_state;
-
- pdata = spi->dev.parent->parent->platform_data;
-
- if (value == BITBANG_CS_INACTIVE) {
- if (pdata->cs_control)
- pdata->cs_control(spi, false);
- }
-
- if (value == BITBANG_CS_ACTIVE) {
- 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;
-
- fsl_spi_change_mode(spi);
-
- if (pdata->cs_control)
- pdata->cs_control(spi, true);
- }
-}
-
static void fsl_spi_qe_cpu_set_shifts(u32 *rx_shift, u32 *tx_shift,
int bits_per_word, int msb_first)
{
@@ -354,15 +328,11 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
return mpc8xxx_spi->count;
}

-static int fsl_spi_do_one_msg(struct spi_master *master,
- struct spi_message *m)
+static int fsl_spi_prepare_message(struct spi_controller *ctlr,
+ struct spi_message *m)
{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
- struct spi_device *spi = m->spi;
- struct spi_transfer *t, *first;
- unsigned int cs_change;
- const int nsecs = 50;
- int status, last_bpw;
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(ctlr);
+ struct spi_transfer *t;

/*
* In CPU mode, optimize large byte transfers to use larger
@@ -378,62 +348,30 @@ static int fsl_spi_do_one_msg(struct spi_master *master,
t->bits_per_word = 16;
}
}
+ return 0;
+}

- /* Don't allow changes if CS is active */
- cs_change = 1;
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (cs_change)
- first = t;
- cs_change = t->cs_change;
- if (first->speed_hz != t->speed_hz) {
- dev_err(&spi->dev,
- "speed_hz cannot change while CS is active\n");
- return -EINVAL;
- }
- }
-
- last_bpw = -1;
- cs_change = 1;
- status = -EINVAL;
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (cs_change || last_bpw != t->bits_per_word)
- status = fsl_spi_setup_transfer(spi, t);
- if (status < 0)
- break;
- last_bpw = t->bits_per_word;
-
- if (cs_change) {
- fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE);
- ndelay(nsecs);
- }
- cs_change = t->cs_change;
- if (t->len)
- status = fsl_spi_bufs(spi, t, m->is_dma_mapped);
- if (status) {
- status = -EMSGSIZE;
- break;
- }
- m->actual_length += t->len;
-
- spi_transfer_delay_exec(t);
-
- if (cs_change) {
- ndelay(nsecs);
- fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
- ndelay(nsecs);
- }
- }
+static int fsl_spi_transfer_one(struct spi_controller *controller,
+ struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ int status;

- m->status = status;
+ status = fsl_spi_setup_transfer(spi, t);
+ if (status < 0)
+ return status;
+ if (t->len)
+ status = fsl_spi_bufs(spi, t, !!t->tx_dma || !!t->rx_dma);
+ if (status > 0)
+ return -EMSGSIZE;

- if (status || !cs_change) {
- ndelay(nsecs);
- fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
- }
+ return status;
+}

- fsl_spi_setup_transfer(spi, NULL);
- spi_finalize_current_message(master);
- return 0;
+static int fsl_spi_unprepare_message(struct spi_controller *controller,
+ struct spi_message *msg)
+{
+ return fsl_spi_setup_transfer(msg->spi, NULL);
}

static int fsl_spi_setup(struct spi_device *spi)
@@ -482,9 +420,6 @@ static int fsl_spi_setup(struct spi_device *spi)
return retval;
}

- /* Initialize chipselect - might be active for SPI_CS_HIGH mode */
- fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
-
return 0;
}

@@ -557,9 +492,7 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
u32 slvsel;
u16 cs = spi->chip_select;

- if (spi->cs_gpiod) {
- gpiod_set_value(spi->cs_gpiod, on);
- } else if (cs < mpc8xxx_spi->native_chipselects) {
+ if (cs < mpc8xxx_spi->native_chipselects) {
slvsel = mpc8xxx_spi_read_reg(&reg_base->slvsel);
slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs));
mpc8xxx_spi_write_reg(&reg_base->slvsel, slvsel);
@@ -568,7 +501,6 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)

static void fsl_spi_grlib_probe(struct device *dev)
{
- struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct spi_master *master = dev_get_drvdata(dev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
@@ -588,7 +520,18 @@ static void fsl_spi_grlib_probe(struct device *dev)
mpc8xxx_spi_write_reg(&reg_base->slvsel, 0xffffffff);
}
master->num_chipselect = mpc8xxx_spi->native_chipselects;
- pdata->cs_control = fsl_spi_grlib_cs_control;
+ master->set_cs = fsl_spi_grlib_cs_control;
+}
+
+static void fsl_spi_cs_control(struct spi_device *spi, bool on)
+{
+ struct device *dev = spi->dev.parent->parent;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
+ struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+
+ if (WARN_ON_ONCE(!pinfo->immr_spi_cs))
+ return;
+ iowrite32be(on ? 0 : SPI_BOOT_SEL_BIT, pinfo->immr_spi_cs);
}

static struct spi_master *fsl_spi_probe(struct device *dev,
@@ -613,8 +556,11 @@ static struct spi_master *fsl_spi_probe(struct device *dev,

master->setup = fsl_spi_setup;
master->cleanup = fsl_spi_cleanup;
- master->transfer_one_message = fsl_spi_do_one_msg;
+ master->prepare_message = fsl_spi_prepare_message;
+ master->transfer_one = fsl_spi_transfer_one;
+ master->unprepare_message = fsl_spi_unprepare_message;
master->use_gpio_descriptors = true;
+ master->set_cs = fsl_spi_cs_control;

mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->max_bits_per_word = 32;
@@ -688,21 +634,6 @@ static struct spi_master *fsl_spi_probe(struct device *dev,
return ERR_PTR(ret);
}

-static void fsl_spi_cs_control(struct spi_device *spi, bool on)
-{
- if (spi->cs_gpiod) {
- gpiod_set_value(spi->cs_gpiod, on);
- } else {
- struct device *dev = spi->dev.parent->parent;
- struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
- struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-
- if (WARN_ON_ONCE(!pinfo->immr_spi_cs))
- return;
- iowrite32be(on ? 0 : SPI_BOOT_SEL_BIT, pinfo->immr_spi_cs);
- }
-}
-
static int of_fsl_spi_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
@@ -744,12 +675,10 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
ret = gpiod_count(dev, "cs");
if (ret < 0)
ret = 0;
- if (ret == 0 && !spisel_boot) {
+ if (ret == 0 && !spisel_boot)
pdata->max_chipselect = 1;
- } else {
+ else
pdata->max_chipselect = ret + spisel_boot;
- pdata->cs_control = fsl_spi_cs_control;
- }
}

ret = of_address_to_resource(np, 0, &mem);
--
2.37.1