diff options
Diffstat (limited to 'drivers/spi/spi-fsl-espi.c')
| -rw-r--r-- | drivers/spi/spi-fsl-espi.c | 111 |
1 files changed, 97 insertions, 14 deletions
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 80d8f40f7e0..8ebd724e4c5 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -219,13 +219,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; unsigned int len = t->len; - u8 bits_per_word; int ret; - bits_per_word = spi->bits_per_word; - if (t->bits_per_word) - bits_per_word = t->bits_per_word; - mpc8xxx_spi->len = t->len; len = roundup(len, 4) / 4; @@ -353,7 +348,7 @@ static void fsl_espi_cmd_trans(struct spi_message *m, } espi_trans->tx_buf = local_buf; - espi_trans->rx_buf = local_buf + espi_trans->n_tx; + espi_trans->rx_buf = local_buf; fsl_espi_do_trans(m, espi_trans); espi_trans->actual_length = espi_trans->len; @@ -402,7 +397,7 @@ static void fsl_espi_rw_trans(struct spi_message *m, espi_trans->n_rx = trans_len; espi_trans->len = trans_len + n_tx; espi_trans->tx_buf = local_buf; - espi_trans->rx_buf = local_buf + n_tx; + espi_trans->rx_buf = local_buf; fsl_espi_do_trans(m, espi_trans); memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len); @@ -446,7 +441,8 @@ static void fsl_espi_do_one_msg(struct spi_message *m) m->actual_length = espi_trans.actual_length; m->status = espi_trans.status; - m->complete(m->context); + if (m->complete) + m->complete(m->context); } static int fsl_espi_setup(struct spi_device *spi) @@ -462,7 +458,7 @@ static int fsl_espi_setup(struct spi_device *spi) return -EINVAL; if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; @@ -590,8 +586,10 @@ static struct spi_master * fsl_espi_probe(struct device *dev, struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; struct fsl_espi_reg *reg_base; - u32 regval; - int i, ret = 0; + struct device_node *nc; + const __be32 *prop; + u32 regval, csmode; + int i, len, ret = 0; master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi)); if (!master) { @@ -638,8 +636,32 @@ static struct spi_master * fsl_espi_probe(struct device *dev, mpc8xxx_spi_write_reg(®_base->event, 0xffffffff); /* Init eSPI CS mode register */ - for (i = 0; i < pdata->max_chipselect; i++) - mpc8xxx_spi_write_reg(®_base->csmode[i], CSMODE_INIT_VAL); + for_each_available_child_of_node(master->dev.of_node, nc) { + /* get chip select */ + prop = of_get_property(nc, "reg", &len); + if (!prop || len < sizeof(*prop)) + continue; + i = be32_to_cpup(prop); + if (i < 0 || i >= pdata->max_chipselect) + continue; + + csmode = CSMODE_INIT_VAL; + /* check if CSBEF is set in device tree */ + prop = of_get_property(nc, "fsl,csbef", &len); + if (prop && len >= sizeof(*prop)) { + csmode &= ~(CSMODE_BEF(0xf)); + csmode |= CSMODE_BEF(be32_to_cpup(prop)); + } + /* check if CSAFT is set in device tree */ + prop = of_get_property(nc, "fsl,csaft", &len); + if (prop && len >= sizeof(*prop)) { + csmode &= ~(CSMODE_AFT(0xf)); + csmode |= CSMODE_AFT(be32_to_cpup(prop)); + } + mpc8xxx_spi_write_reg(®_base->csmode[i], csmode); + + dev_info(dev, "cs=%d, init_csmode=0x%x\n", i, csmode); + } /* Enable SPI interface */ regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; @@ -705,7 +727,7 @@ static int of_fsl_espi_probe(struct platform_device *ofdev) goto err; irq = irq_of_parse_and_map(np, 0); - if (!ret) { + if (!irq) { ret = -EINVAL; goto err; } @@ -727,6 +749,66 @@ static int of_fsl_espi_remove(struct platform_device *dev) return mpc8xxx_spi_remove(&dev->dev); } +#ifdef CONFIG_PM_SLEEP +static int of_fsl_espi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct mpc8xxx_spi *mpc8xxx_spi; + struct fsl_espi_reg *reg_base; + u32 regval; + int ret; + + mpc8xxx_spi = spi_master_get_devdata(master); + reg_base = mpc8xxx_spi->reg_base; + + ret = spi_master_suspend(master); + if (ret) { + dev_warn(dev, "cannot suspend master\n"); + return ret; + } + + regval = mpc8xxx_spi_read_reg(®_base->mode); + regval &= ~SPMODE_ENABLE; + mpc8xxx_spi_write_reg(®_base->mode, regval); + + return 0; +} + +static int of_fsl_espi_resume(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; + struct fsl_espi_reg *reg_base; + u32 regval; + int i; + + mpc8xxx_spi = spi_master_get_devdata(master); + reg_base = mpc8xxx_spi->reg_base; + + /* SPI controller initializations */ + mpc8xxx_spi_write_reg(®_base->mode, 0); + mpc8xxx_spi_write_reg(®_base->mask, 0); + mpc8xxx_spi_write_reg(®_base->command, 0); + mpc8xxx_spi_write_reg(®_base->event, 0xffffffff); + + /* Init eSPI CS mode register */ + for (i = 0; i < pdata->max_chipselect; i++) + mpc8xxx_spi_write_reg(®_base->csmode[i], CSMODE_INIT_VAL); + + /* Enable SPI interface */ + regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; + + mpc8xxx_spi_write_reg(®_base->mode, regval); + + return spi_master_resume(master); +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops espi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume) +}; + static const struct of_device_id of_fsl_espi_match[] = { { .compatible = "fsl,mpc8536-espi" }, {} @@ -738,6 +820,7 @@ static struct platform_driver fsl_espi_driver = { .name = "fsl_espi", .owner = THIS_MODULE, .of_match_table = of_fsl_espi_match, + .pm = &espi_pm, }, .probe = of_fsl_espi_probe, .remove = of_fsl_espi_remove, |
