summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-fsl-spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-fsl-spi.c')
-rw-r--r--drivers/spi/spi-fsl-spi.c333
1 files changed, 128 insertions, 205 deletions
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index bdf94cc7be1a..2f2082652a1a 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -88,7 +88,7 @@ static int fsl_spi_get_type(struct device *dev)
static void fsl_spi_change_mode(struct spi_device *spi)
{
- struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mspi = spi_controller_get_devdata(spi->controller);
struct spi_mpc8xxx_cs *cs = spi->controller_state;
struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
__be32 __iomem *mode = &reg_base->mode;
@@ -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)
{
@@ -171,10 +145,10 @@ static void fsl_spi_grlib_set_shifts(u32 *rx_shift, u32 *tx_shift,
}
}
-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)
+static void mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
+ struct spi_device *spi,
+ struct mpc8xxx_spi *mpc8xxx_spi,
+ int bits_per_word)
{
cs->rx_shift = 0;
cs->tx_shift = 0;
@@ -187,8 +161,7 @@ static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
} else if (bits_per_word <= 32) {
cs->get_rx = mpc8xxx_spi_rx_buf_u32;
cs->get_tx = mpc8xxx_spi_tx_buf_u32;
- } else
- return -EINVAL;
+ }
if (mpc8xxx_spi->set_shifts)
mpc8xxx_spi->set_shifts(&cs->rx_shift, &cs->tx_shift,
@@ -199,26 +172,6 @@ static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
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 fsl_spi_setup_transfer(struct spi_device *spi,
@@ -230,7 +183,7 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
u32 hz = 0;
struct spi_mpc8xxx_cs *cs = spi->controller_state;
- mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
if (t) {
bits_per_word = t->bits_per_word;
@@ -245,15 +198,7 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
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;
+ mspi_apply_cpu_mode_quirks(cs, spi, mpc8xxx_spi, bits_per_word);
if (bits_per_word == 32)
bits_per_word = 0;
@@ -304,10 +249,9 @@ static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
return 0;
}
-static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
- bool is_dma_mapped)
+static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
struct fsl_spi_reg __iomem *reg_base;
unsigned int len = t->len;
u8 bits_per_word;
@@ -318,18 +262,10 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
- if (bits_per_word > 8) {
- /* invalid length? */
- if (len & 1)
- return -EINVAL;
+ if (bits_per_word > 8)
len /= 2;
- }
- if (bits_per_word > 16) {
- /* invalid length? */
- if (len & 1)
- return -EINVAL;
+ if (bits_per_word > 16)
len /= 2;
- }
mpc8xxx_spi->tx = t->tx_buf;
mpc8xxx_spi->rx = t->rx_buf;
@@ -337,7 +273,7 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
reinit_completion(&mpc8xxx_spi->done);
if (mpc8xxx_spi->flags & SPI_CPM_MODE)
- ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
+ ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t);
else
ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len);
if (ret)
@@ -354,86 +290,79 @@ 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;
+ struct spi_transfer *first;
+
+ first = list_first_entry(&m->transfers, struct spi_transfer,
+ transfer_list);
/*
* In CPU mode, optimize large byte transfers to use larger
* bits_per_word values to reduce number of interrupts taken.
+ *
+ * Some glitches can appear on the SPI clock when the mode changes.
+ * Check that there is no speed change during the transfer and set it up
+ * now to change the mode without having a chip-select asserted.
*/
- if (!(mpc8xxx_spi->flags & SPI_CPM_MODE)) {
- list_for_each_entry(t, &m->transfers, transfer_list) {
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->speed_hz != first->speed_hz) {
+ dev_err(&m->spi->dev,
+ "speed_hz cannot change during message.\n");
+ return -EINVAL;
+ }
+ if (!(mpc8xxx_spi->flags & SPI_CPM_MODE)) {
if (t->len < 256 || t->bits_per_word != 8)
continue;
if ((t->len & 3) == 0)
t->bits_per_word = 32;
else if ((t->len & 1) == 0)
t->bits_per_word = 16;
+ } else {
+ /*
+ * CPM/QE uses Little Endian for words > 8
+ * so transform 16 and 32 bits words 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 (m->spi->mode & SPI_LSB_FIRST && t->bits_per_word > 8)
+ return -EINVAL;
+ if (t->bits_per_word == 16 || t->bits_per_word == 32)
+ t->bits_per_word = 8; /* pretend its 8 bits */
+ if (t->bits_per_word == 8 && t->len >= 256 &&
+ (mpc8xxx_spi->flags & SPI_CPM1))
+ t->bits_per_word = 16;
}
}
+ return fsl_spi_setup_transfer(m->spi, first);
+}
- /* 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);
+ 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)
@@ -455,7 +384,7 @@ static int fsl_spi_setup(struct spi_device *spi)
spi_set_ctldata(spi, cs);
initial_setup = true;
}
- mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
reg_base = mpc8xxx_spi->reg_base;
@@ -482,9 +411,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;
}
@@ -552,14 +478,12 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
u32 slvsel;
- u16 cs = spi->chip_select;
+ u16 cs = spi_get_chipselect(spi, 0);
- 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,9 +492,8 @@ 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 spi_controller *host = dev_get_drvdata(dev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
int mbits;
u32 capabilities;
@@ -587,36 +510,50 @@ static void fsl_spi_grlib_probe(struct device *dev)
mpc8xxx_spi->native_chipselects = SPCAP_SSSZ(capabilities);
mpc8xxx_spi_write_reg(&reg_base->slvsel, 0xffffffff);
}
- master->num_chipselect = mpc8xxx_spi->native_chipselects;
- pdata->cs_control = fsl_spi_grlib_cs_control;
+ host->num_chipselect = mpc8xxx_spi->native_chipselects;
+ host->set_cs = fsl_spi_grlib_cs_control;
}
-static struct spi_master *fsl_spi_probe(struct device *dev,
+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_controller *fsl_spi_probe(struct device *dev,
struct resource *mem, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
- struct spi_master *master;
+ struct spi_controller *host;
struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_spi_reg __iomem *reg_base;
u32 regval;
int ret = 0;
- master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
- if (master == NULL) {
+ host = spi_alloc_host(dev, sizeof(struct mpc8xxx_spi));
+ if (host == NULL) {
ret = -ENOMEM;
goto err;
}
- dev_set_drvdata(dev, master);
+ dev_set_drvdata(dev, host);
mpc8xxx_spi_probe(dev, mem, irq);
- master->setup = fsl_spi_setup;
- master->cleanup = fsl_spi_cleanup;
- master->transfer_one_message = fsl_spi_do_one_msg;
- master->use_gpio_descriptors = true;
+ host->setup = fsl_spi_setup;
+ host->cleanup = fsl_spi_cleanup;
+ host->prepare_message = fsl_spi_prepare_message;
+ host->transfer_one = fsl_spi_transfer_one;
+ host->unprepare_message = fsl_spi_unprepare_message;
+ host->use_gpio_descriptors = true;
+ host->set_cs = fsl_spi_cs_control;
- mpc8xxx_spi = spi_master_get_devdata(master);
+ mpc8xxx_spi = spi_controller_get_devdata(host);
mpc8xxx_spi->max_bits_per_word = 32;
mpc8xxx_spi->type = fsl_spi_get_type(dev);
@@ -633,8 +570,14 @@ static struct spi_master *fsl_spi_probe(struct device *dev,
if (mpc8xxx_spi->type == TYPE_GRLIB)
fsl_spi_grlib_probe(dev);
- master->bits_per_word_mask =
- (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) &
+ if (mpc8xxx_spi->flags & SPI_CPM_MODE)
+ host->bits_per_word_mask =
+ (SPI_BPW_RANGE_MASK(4, 8) | SPI_BPW_MASK(16) | SPI_BPW_MASK(32));
+ else
+ host->bits_per_word_mask =
+ (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32));
+
+ host->bits_per_word_mask &=
SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word);
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
@@ -671,43 +614,28 @@ static struct spi_master *fsl_spi_probe(struct device *dev,
mpc8xxx_spi_write_reg(&reg_base->mode, regval);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret < 0)
goto err_probe;
- dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
+ dev_info(dev, "at MMIO %pa (irq = %d), %s mode\n", &mem->start,
mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
- return master;
+ return host;
err_probe:
fsl_spi_cpm_free(mpc8xxx_spi);
err_cpm_init:
- spi_master_put(master);
+ spi_controller_put(host);
err:
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;
struct device_node *np = ofdev->dev.of_node;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource mem;
int irq, type;
int ret;
@@ -744,12 +672,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);
@@ -762,9 +688,9 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
goto unmap_out;
}
- master = fsl_spi_probe(dev, &mem, irq);
+ host = fsl_spi_probe(dev, &mem, irq);
- return PTR_ERR_OR_ZERO(master);
+ return PTR_ERR_OR_ZERO(host);
unmap_out:
#if IS_ENABLED(CONFIG_FSL_SOC)
@@ -774,13 +700,12 @@ unmap_out:
return ret;
}
-static int of_fsl_spi_remove(struct platform_device *ofdev)
+static void of_fsl_spi_remove(struct platform_device *ofdev)
{
- struct spi_master *master = platform_get_drvdata(ofdev);
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(ofdev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
fsl_spi_cpm_free(mpc8xxx_spi);
- return 0;
}
static struct platform_driver of_fsl_spi_driver = {
@@ -804,7 +729,7 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
{
struct resource *mem;
int irq;
- struct spi_master *master;
+ struct spi_controller *host;
if (!dev_get_platdata(&pdev->dev))
return -EINVAL;
@@ -814,21 +739,19 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
return -EINVAL;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -EINVAL;
+ if (irq < 0)
+ return irq;
- master = fsl_spi_probe(&pdev->dev, mem, irq);
- return PTR_ERR_OR_ZERO(master);
+ host = fsl_spi_probe(&pdev->dev, mem, irq);
+ return PTR_ERR_OR_ZERO(host);
}
-static int plat_mpc8xxx_spi_remove(struct platform_device *pdev)
+static void plat_mpc8xxx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
fsl_spi_cpm_free(mpc8xxx_spi);
-
- return 0;
}
MODULE_ALIAS("platform:mpc8xxx_spi");