Commit e5aeced6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'spi-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi updates from Mark Brown:
 "A few core tweaks this time together with the usual collection of
  driver specific updates and fixes plus a larger than average selection
  of new device support:

   - fix DMA mapping of unaligned vmalloc() buffers

   - statistics tracking transfer volumes exposed via sysfs

   - new drivers for Freescale MPC5125, Intel Sunrise Point, Mediatek
     SoCs, and Netlogic XLP SoCs"

* tag 'spi-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (66 commits)
  spi: sh-msiof: Fix FIFO size to 64 word from 256 word
  spi: fsl-(e)spi: Fix checking return value of devm_ioremap_resource
  spi: Add DT bindings documentation for Netlogic XLP SPI controller
  spi/xlp: SPI controller driver for Netlogic XLP SoCs
  spi: fsl-espi: add runtime PM
  spi: fsl-(e)spi: simplify cleanup code
  spi: fsl-(e)spi: migrate to using devm_ functions to simplify cleanup
  spi: mediatek: fix SPI_CMD_PAUSE_IE macro error
  spi: check bits_per_word in spi_setup
  spi: mediatek: replace *_time name
  spi: mediatek: add PM clk_prepare_enable fail flow
  spi: mediatek: replace int with u32, delete TAB and define MTK_SPI_PAUSE_INT_STATUS marco
  spi: mediatek: add linux/io.h include file
  spi/bcm63xx-hsspi: add support for dual spi read/write
  spi: dw: Allow interface drivers to limit data I/O to word sizes
  dt: snps,dw-apb-ssi: Document new I/O data register width property
  spi: Fall back to master maximum speed if no slave speed specified
  spi: mediatek: use BIT() to instead of SPI_CMD_*_OFFSET
  spi: medaitek: revise quirks compatibility style
  spi: mediatek: fix spi incorrect endian usage
  ...
parents cf9d615f c5992f61
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/pm_runtime.h>
#include <sysdev/fsl_soc.h> #include <sysdev/fsl_soc.h>
#include "spi-fsl-lib.h" #include "spi-fsl-lib.h"
...@@ -85,6 +86,8 @@ struct fsl_espi_transfer { ...@@ -85,6 +86,8 @@ struct fsl_espi_transfer {
#define SPCOM_TRANLEN(x) ((x) << 0) #define SPCOM_TRANLEN(x) ((x) << 0)
#define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */ #define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */
#define AUTOSUSPEND_TIMEOUT 2000
static void fsl_espi_change_mode(struct spi_device *spi) static void fsl_espi_change_mode(struct spi_device *spi)
{ {
struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
...@@ -485,6 +488,8 @@ static int fsl_espi_setup(struct spi_device *spi) ...@@ -485,6 +488,8 @@ static int fsl_espi_setup(struct spi_device *spi)
mpc8xxx_spi = spi_master_get_devdata(spi->master); mpc8xxx_spi = spi_master_get_devdata(spi->master);
reg_base = mpc8xxx_spi->reg_base; reg_base = mpc8xxx_spi->reg_base;
pm_runtime_get_sync(mpc8xxx_spi->dev);
hw_mode = cs->hw_mode; /* Save original settings */ hw_mode = cs->hw_mode; /* Save original settings */
cs->hw_mode = mpc8xxx_spi_read_reg( cs->hw_mode = mpc8xxx_spi_read_reg(
&reg_base->csmode[spi->chip_select]); &reg_base->csmode[spi->chip_select]);
...@@ -507,6 +512,10 @@ static int fsl_espi_setup(struct spi_device *spi) ...@@ -507,6 +512,10 @@ static int fsl_espi_setup(struct spi_device *spi)
mpc8xxx_spi_write_reg(&reg_base->mode, loop_mode); mpc8xxx_spi_write_reg(&reg_base->mode, loop_mode);
retval = fsl_espi_setup_transfer(spi, NULL); retval = fsl_espi_setup_transfer(spi, NULL);
pm_runtime_mark_last_busy(mpc8xxx_spi->dev);
pm_runtime_put_autosuspend(mpc8xxx_spi->dev);
if (retval < 0) { if (retval < 0) {
cs->hw_mode = hw_mode; /* Restore settings */ cs->hw_mode = hw_mode; /* Restore settings */
return retval; return retval;
...@@ -604,20 +613,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) ...@@ -604,20 +613,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
return ret; return ret;
} }
static void fsl_espi_remove(struct mpc8xxx_spi *mspi) #ifdef CONFIG_PM
static int fsl_espi_runtime_suspend(struct device *dev)
{ {
iounmap(mspi->reg_base); struct spi_master *master = dev_get_drvdata(dev);
} struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
static int fsl_espi_suspend(struct spi_master *master)
{
struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_espi_reg *reg_base;
u32 regval; u32 regval;
mpc8xxx_spi = spi_master_get_devdata(master);
reg_base = mpc8xxx_spi->reg_base;
regval = mpc8xxx_spi_read_reg(&reg_base->mode); regval = mpc8xxx_spi_read_reg(&reg_base->mode);
regval &= ~SPMODE_ENABLE; regval &= ~SPMODE_ENABLE;
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
...@@ -625,21 +628,20 @@ static int fsl_espi_suspend(struct spi_master *master) ...@@ -625,21 +628,20 @@ static int fsl_espi_suspend(struct spi_master *master)
return 0; return 0;
} }
static int fsl_espi_resume(struct spi_master *master) static int fsl_espi_runtime_resume(struct device *dev)
{ {
struct mpc8xxx_spi *mpc8xxx_spi; struct spi_master *master = dev_get_drvdata(dev);
struct fsl_espi_reg *reg_base; struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
u32 regval; u32 regval;
mpc8xxx_spi = spi_master_get_devdata(master);
reg_base = mpc8xxx_spi->reg_base;
regval = mpc8xxx_spi_read_reg(&reg_base->mode); regval = mpc8xxx_spi_read_reg(&reg_base->mode);
regval |= SPMODE_ENABLE; regval |= SPMODE_ENABLE;
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
return 0; return 0;
} }
#endif
static struct spi_master * fsl_espi_probe(struct device *dev, static struct spi_master * fsl_espi_probe(struct device *dev,
struct resource *mem, unsigned int irq) struct resource *mem, unsigned int irq)
...@@ -667,25 +669,23 @@ static struct spi_master * fsl_espi_probe(struct device *dev, ...@@ -667,25 +669,23 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
master->setup = fsl_espi_setup; master->setup = fsl_espi_setup;
master->cleanup = fsl_espi_cleanup; master->cleanup = fsl_espi_cleanup;
master->transfer_one_message = fsl_espi_do_one_msg; master->transfer_one_message = fsl_espi_do_one_msg;
master->prepare_transfer_hardware = fsl_espi_resume; master->auto_runtime_pm = true;
master->unprepare_transfer_hardware = fsl_espi_suspend;
mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->spi_remove = fsl_espi_remove;
mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
if (!mpc8xxx_spi->reg_base) { if (IS_ERR(mpc8xxx_spi->reg_base)) {
ret = -ENOMEM; ret = PTR_ERR(mpc8xxx_spi->reg_base);
goto err_probe; goto err_probe;
} }
reg_base = mpc8xxx_spi->reg_base; reg_base = mpc8xxx_spi->reg_base;
/* Register for SPI Interrupt */ /* Register for SPI Interrupt */
ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq, ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_espi_irq,
0, "fsl_espi", mpc8xxx_spi); 0, "fsl_espi", mpc8xxx_spi);
if (ret) if (ret)
goto free_irq; goto err_probe;
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
mpc8xxx_spi->rx_shift = 16; mpc8xxx_spi->rx_shift = 16;
...@@ -731,18 +731,27 @@ static struct spi_master * fsl_espi_probe(struct device *dev, ...@@ -731,18 +731,27 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
ret = spi_register_master(master); pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
ret = devm_spi_register_master(dev, master);
if (ret < 0) if (ret < 0)
goto unreg_master; goto err_pm;
dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq); dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return master; return master;
unreg_master: err_pm:
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); pm_runtime_put_noidle(dev);
free_irq: pm_runtime_disable(dev);
iounmap(mpc8xxx_spi->reg_base); pm_runtime_set_suspended(dev);
err_probe: err_probe:
spi_master_put(master); spi_master_put(master);
err: err:
...@@ -809,7 +818,9 @@ static int of_fsl_espi_probe(struct platform_device *ofdev) ...@@ -809,7 +818,9 @@ static int of_fsl_espi_probe(struct platform_device *ofdev)
static int of_fsl_espi_remove(struct platform_device *dev) static int of_fsl_espi_remove(struct platform_device *dev)
{ {
return mpc8xxx_spi_remove(&dev->dev); pm_runtime_disable(&dev->dev);
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -824,7 +835,11 @@ static int of_fsl_espi_suspend(struct device *dev) ...@@ -824,7 +835,11 @@ static int of_fsl_espi_suspend(struct device *dev)
return ret; return ret;
} }
return fsl_espi_suspend(master); ret = pm_runtime_force_suspend(dev);
if (ret < 0)
return ret;
return 0;
} }
static int of_fsl_espi_resume(struct device *dev) static int of_fsl_espi_resume(struct device *dev)
...@@ -834,7 +849,7 @@ static int of_fsl_espi_resume(struct device *dev) ...@@ -834,7 +849,7 @@ static int of_fsl_espi_resume(struct device *dev)
struct mpc8xxx_spi *mpc8xxx_spi; struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_espi_reg *reg_base; struct fsl_espi_reg *reg_base;
u32 regval; u32 regval;
int i; int i, ret;
mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi = spi_master_get_devdata(master);
reg_base = mpc8xxx_spi->reg_base; reg_base = mpc8xxx_spi->reg_base;
...@@ -854,11 +869,17 @@ static int of_fsl_espi_resume(struct device *dev) ...@@ -854,11 +869,17 @@ static int of_fsl_espi_resume(struct device *dev)
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
ret = pm_runtime_force_resume(dev);
if (ret < 0)
return ret;
return spi_master_resume(master); return spi_master_resume(master);
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops espi_pm = { static const struct dev_pm_ops espi_pm = {
SET_RUNTIME_PM_OPS(fsl_espi_runtime_suspend,
fsl_espi_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume) SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume)
}; };
......
...@@ -114,25 +114,6 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, ...@@ -114,25 +114,6 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
} }
EXPORT_SYMBOL_GPL(mpc8xxx_spi_probe); EXPORT_SYMBOL_GPL(mpc8xxx_spi_probe);
int mpc8xxx_spi_remove(struct device *dev)
{
struct mpc8xxx_spi *mpc8xxx_spi;
struct spi_master *master;
master = dev_get_drvdata(dev);
mpc8xxx_spi = spi_master_get_devdata(master);
spi_unregister_master(master);
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
if (mpc8xxx_spi->spi_remove)
mpc8xxx_spi->spi_remove(mpc8xxx_spi);
return 0;
}
EXPORT_SYMBOL_GPL(mpc8xxx_spi_remove);
int of_mpc8xxx_spi_probe(struct platform_device *ofdev) int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
{ {
struct device *dev = &ofdev->dev; struct device *dev = &ofdev->dev;
......
...@@ -54,9 +54,6 @@ struct mpc8xxx_spi { ...@@ -54,9 +54,6 @@ struct mpc8xxx_spi {
void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
u32(*get_tx) (struct mpc8xxx_spi *); u32(*get_tx) (struct mpc8xxx_spi *);
/* hooks for different controller driver */
void (*spi_remove) (struct mpc8xxx_spi *mspi);
unsigned int count; unsigned int count;
unsigned int irq; unsigned int irq;
......
...@@ -559,12 +559,6 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data) ...@@ -559,12 +559,6 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
return ret; return ret;
} }
static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
{
iounmap(mspi->reg_base);
fsl_spi_cpm_free(mspi);
}
static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) 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_master_get_devdata(spi->master);
...@@ -631,7 +625,6 @@ static struct spi_master * fsl_spi_probe(struct device *dev, ...@@ -631,7 +625,6 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
master->transfer_one_message = fsl_spi_do_one_msg; master->transfer_one_message = fsl_spi_do_one_msg;
mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->spi_remove = fsl_spi_remove;
mpc8xxx_spi->max_bits_per_word = 32; mpc8xxx_spi->max_bits_per_word = 32;
mpc8xxx_spi->type = fsl_spi_get_type(dev); mpc8xxx_spi->type = fsl_spi_get_type(dev);
...@@ -639,10 +632,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev, ...@@ -639,10 +632,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
if (ret) if (ret)
goto err_cpm_init; goto err_cpm_init;
mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
if (mpc8xxx_spi->reg_base == NULL) { if (IS_ERR(mpc8xxx_spi->reg_base)) {
ret = -ENOMEM; ret = PTR_ERR(mpc8xxx_spi->reg_base);
goto err_ioremap; goto err_probe;
} }
if (mpc8xxx_spi->type == TYPE_GRLIB) if (mpc8xxx_spi->type == TYPE_GRLIB)
...@@ -661,11 +654,11 @@ static struct spi_master * fsl_spi_probe(struct device *dev, ...@@ -661,11 +654,11 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
&mpc8xxx_spi->tx_shift, 8, 1); &mpc8xxx_spi->tx_shift, 8, 1);
/* Register for SPI Interrupt */ /* Register for SPI Interrupt */
ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq, ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_spi_irq,
0, "fsl_spi", mpc8xxx_spi); 0, "fsl_spi", mpc8xxx_spi);
if (ret != 0) if (ret != 0)
goto free_irq; goto err_probe;
reg_base = mpc8xxx_spi->reg_base; reg_base = mpc8xxx_spi->reg_base;
...@@ -686,20 +679,16 @@ static struct spi_master * fsl_spi_probe(struct device *dev, ...@@ -686,20 +679,16 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
ret = spi_register_master(master); ret = devm_spi_register_master(dev, master);
if (ret < 0) if (ret < 0)
goto unreg_master; goto err_probe;
dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base, dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags)); mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
return master; return master;
unreg_master: err_probe:
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
free_irq:
iounmap(mpc8xxx_spi->reg_base);
err_ioremap:
fsl_spi_cpm_free(mpc8xxx_spi); fsl_spi_cpm_free(mpc8xxx_spi);
err_cpm_init: err_cpm_init:
spi_master_put(master); spi_master_put(master);
...@@ -866,11 +855,8 @@ static int of_fsl_spi_remove(struct platform_device *ofdev) ...@@ -866,11 +855,8 @@ static int of_fsl_spi_remove(struct platform_device *ofdev)
{ {
struct spi_master *master = platform_get_drvdata(ofdev); struct spi_master *master = platform_get_drvdata(ofdev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
int ret;
ret = mpc8xxx_spi_remove(&ofdev->dev); fsl_spi_cpm_free(mpc8xxx_spi);
if (ret)
return ret;
if (mpc8xxx_spi->type == TYPE_FSL) if (mpc8xxx_spi->type == TYPE_FSL)
of_fsl_spi_free_chipselects(&ofdev->dev); of_fsl_spi_free_chipselects(&ofdev->dev);
return 0; return 0;
...@@ -916,7 +902,12 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev) ...@@ -916,7 +902,12 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
static int plat_mpc8xxx_spi_remove(struct platform_device *pdev) static int plat_mpc8xxx_spi_remove(struct platform_device *pdev)
{ {
return mpc8xxx_spi_remove(&pdev->dev); struct spi_master *master = platform_get_drvdata(pdev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
fsl_spi_cpm_free(mpc8xxx_spi);
return 0;
} }
MODULE_ALIAS("platform:mpc8xxx_spi"); MODULE_ALIAS("platform:mpc8xxx_spi");
......
...@@ -105,6 +105,10 @@ struct img_spfi { ...@@ -105,6 +105,10 @@ struct img_spfi {
bool rx_dma_busy; bool rx_dma_busy;
}; };
struct img_spfi_device_data {
bool gpio_requested;
};
static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
{ {
return readl(spfi->regs + reg); return readl(spfi->regs + reg);
...@@ -267,15 +271,15 @@ static int img_spfi_start_pio(struct spi_master *master, ...@@ -267,15 +271,15 @@ static int img_spfi_start_pio(struct spi_master *master,
cpu_relax(); cpu_relax();
} }
ret = spfi_wait_all_done(spfi);
if (ret < 0)
return ret;
if (rx_bytes > 0 || tx_bytes > 0) { if (rx_bytes > 0 || tx_bytes > 0) {
dev_err(spfi->dev, "PIO transfer timed out\n"); dev_err(spfi->dev, "PIO transfer timed out\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
ret = spfi_wait_all_done(spfi);
if (ret < 0)
return ret;
return 0; return 0;
} }
...@@ -440,21 +444,50 @@ static int img_spfi_unprepare(struct spi_master *master, ...@@ -440,21 +444,50 @@ static int img_spfi_unprepare(struct spi_master *master,
static int img_spfi_setup(struct spi_device *spi) static int img_spfi_setup(struct spi_device *spi)
{ {
int ret; int ret = -EINVAL;
struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);
ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, if (!spfi_data) {
dev_name(&spi->dev)); spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL);
if (ret) if (!spfi_data)
dev_err(&spi->dev, "can't request chipselect gpio %d\n", return -ENOMEM;
spfi_data->gpio_requested = false;
spi_set_ctldata(spi, spfi_data);
}
if (!spfi_data->gpio_requested) {
ret = gpio_request_one(spi->cs_gpio,
(spi->mode & SPI_CS_HIGH) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
dev_name(&spi->dev));
if (ret)
dev_err(&spi->dev, "can't request chipselect gpio %d\n",
spi->cs_gpio); spi->cs_gpio);
else
spfi_data->gpio_requested = true;
} else {
if (gpio_is_valid(spi->cs_gpio)) {
int mode = ((spi->mode & SPI_CS_HIGH) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);
ret = gpio_direction_output(spi->cs_gpio, mode);
if (ret)
dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n",
spi->cs_gpio, ret);
}
}
return ret; return ret;
} }
static void img_spfi_cleanup(struct spi_device *spi) static void img_spfi_cleanup(struct spi_device *spi)
{ {
gpio_free(spi->cs_gpio); struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);
if (spfi_data) {
if (spfi_data->gpio_requested)
gpio_free(spi->cs_gpio);
kfree(spfi_data);
spi_set_ctldata(spi, NULL);
}
} }
static void img_spfi_config(struct spi_master *master, struct spi_device *spi, static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
...@@ -548,6 +581,7 @@ static int img_spfi_probe(struct platform_device *pdev) ...@@ -548,6 +581,7 @@ static int img_spfi_probe(struct platform_device *pdev)
struct img_spfi *spfi; struct img_spfi *spfi;
struct resource *res; struct resource *res;
int ret; int ret;
u32 max_speed_hz;
master = spi_alloc_master(&pdev->dev, sizeof(*spfi)); master = spi_alloc_master(&pdev->dev, sizeof(*spfi));
if (!master) if (!master)
...@@ -612,6 +646,19 @@ static int img_spfi_probe(struct platform_device *pdev) ...@@ -612,6 +646,19 @@ static int img_spfi_probe(struct platform_device *pdev)
master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4; master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512; master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
/*
* Maximum speed supported by spfi is limited to the lower value
* between 1/4 of the SPFI clock or to "spfi-max-frequency"
* defined in the device tree.
* If no value is defined in the device tree assume the maximum
* speed supported to be 1/4 of the SPFI clock.
*/
if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency",
&max_speed_hz)) {
if (master->max_speed_hz > max_speed_hz)
master->max_speed_hz = max_speed_hz;
}
master->setup = img_spfi_setup; master->setup = img_spfi_setup;
master->cleanup = img_spfi_cleanup; master->cleanup = img_spfi_cleanup;
master->transfer_one = img_spfi_transfer_one; master->transfer_one = img_spfi_transfer_one;
......
...@@ -30,11 +30,37 @@ ...@@ -30,11 +30,37 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <asm/mpc52xx_psc.h> #include <asm/mpc52xx_psc.h>
enum {
TYPE_MPC5121,
TYPE_MPC5125,
};
/*
* This macro abstracts the differences in the PSC register layout between
* MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc).
*/
#define psc_addr(mps, regname) ({ \
void *__ret = NULL; \
switch (mps->type) { \
case TYPE_MPC5121: { \
struct mpc52xx_psc __iomem *psc = mps->psc; \
__ret = &psc->regname; \
}; \
break; \
case TYPE_MPC5125: { \
struct mpc5125_psc __iomem *psc = mps->psc; \
__ret = &psc->regname; \
}; \
break; \
} \
__ret; })
struct mpc512x_psc_spi { struct mpc512x_psc_spi {
void (*cs_control)(struct spi_device *spi, bool on); void (*cs_control)(struct spi_device *spi, bool on);
/* driver internal data */ /* driver internal data */
struct mpc52xx_psc __iomem *psc; int type;
void __iomem *psc;
struct mpc512x_psc_fifo __iomem *fifo; struct mpc512x_psc_fifo __iomem *fifo;
unsigned int irq; unsigned int irq;
u8 bits_per_word; u8 bits_per_word;
...@@ -71,13 +97,12 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) ...@@ -71,13 +97,12 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
{ {
struct mpc512x_psc_spi_cs *cs = spi->controller_state; struct mpc512x_psc_spi_cs *cs = spi->controller_state;
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc52xx_psc __iomem *psc = mps->psc;
u32 sicr; u32 sicr;
u32 ccr; u32 ccr;
int speed; int speed;
u16 bclkdiv; u16 bclkdiv;
sicr = in_be32(&psc->sicr); sicr = in_be32(psc_addr(mps, sicr));
/* Set clock phase and polarity */ /* Set clock phase and polarity */
if (spi->mode & SPI_CPHA) if (spi->mode & SPI_CPHA)
...@@ -94,9 +119,9 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) ...@@ -94,9 +119,9 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
sicr |= 0x10000000; sicr |= 0x10000000;
else else
sicr &= ~0x10000000; sicr &= ~0x10000000;
out_be32(&psc->sicr, sicr); out_be32(psc_addr(mps, sicr), sicr);
ccr = in_be32(&psc->ccr); ccr = in_be32(psc_addr(mps, ccr));
ccr &= 0xFF000000; ccr &= 0xFF000000;
speed = cs->speed_hz; speed = cs->speed_hz;
if (!speed) if (!speed)
...@@ -104,7 +129,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) ...@@ -104,7 +129,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
bclkdiv = (mps->mclk_rate / speed) - 1; bclkdiv = (mps->mclk_rate / speed) - 1;
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
out_be32(&psc->ccr, ccr); out_be32(psc_addr(mps, ccr), ccr);
mps->bits_per_word = cs->bits_per_word; mps->bits_per_word = cs->bits_per_word;
if (mps->cs_control && gpio_is_valid(spi->cs_gpio)) if (mps->cs_control && gpio_is_valid(spi->cs_gpio))
...@@ -315,16 +340,15 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master, ...@@ -315,16 +340,15 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master) static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
{ {
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
struct mpc52xx_psc __iomem *psc = mps->psc;
dev_dbg(&master->dev, "%s()\n", __func__); dev_dbg(&master->dev, "%s()\n", __func__);
/* Zero MR2 */ /* Zero MR2 */
in_8(&psc->mode); in_8(psc_addr(mps, mr2));
out_8(&psc->mode, 0x0); out_8(psc_addr(mps, mr2), 0x0);
/* enable transmitter/receiver */ /* enable transmitter/receiver */
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); out_8(psc_addr(mps, command), MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
return 0; return 0;
} }
...@@ -332,13 +356,12 @@ static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master) ...@@ -332,13 +356,12 @@ static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master) static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master)
{ {
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
dev_dbg(&master->dev, "%s()\n", __func__); dev_dbg(&master->dev, "%s()\n", __func__);
/* disable transmitter/receiver and fifo interrupt */ /* disable transmitter/receiver and fifo interrupt */
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
out_be32(&fifo->tximr, 0); out_be32(&fifo->tximr, 0);
return 0; return 0;
...@@ -388,7 +411,6 @@ static void mpc512x_psc_spi_cleanup(struct spi_device *spi) ...@@ -388,7 +411,6 @@ static void mpc512x_psc_spi_cleanup(struct spi_device *spi)
static int mpc512x_psc_spi_port_config(struct spi_master *master, static int mpc512x_psc_spi_port_config(struct spi_master *master,
struct mpc512x_psc_spi *mps) struct mpc512x_psc_spi *mps)
{ {
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
u32 sicr; u32 sicr;
u32 ccr; u32 ccr;
...@@ -396,12 +418,12 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, ...@@ -396,12 +418,12 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
u16 bclkdiv; u16 bclkdiv;
/* Reset the PSC into a known state */ /* Reset the PSC into a known state */
out_8(&psc->command, MPC52xx_PSC_RST_RX); out_8(psc_addr(mps, command), MPC52xx_PSC_RST_RX);
out_8(&psc->command, MPC52xx_PSC_RST_TX); out_8(psc_addr(mps, command), MPC52xx_PSC_RST_TX);
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
/* Disable psc interrupts all useful interrupts are in fifo */ /* Disable psc interrupts all useful interrupts are in fifo */
out_be16(&psc->isr_imr.imr, 0); out_be16(psc_addr(mps, isr_imr.imr), 0);
/* Disable fifo interrupts, will be enabled later */ /* Disable fifo interrupts, will be enabled later */
out_be32(&fifo->tximr, 0); out_be32(&fifo->tximr, 0);
...@@ -417,18 +439,18 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, ...@@ -417,18 +439,18 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
0x00004000 | /* MSTR = 1 -- SPI master */ 0x00004000 | /* MSTR = 1 -- SPI master */
0x00000800; /* UseEOF = 1 -- SS low until EOF */ 0x00000800; /* UseEOF = 1 -- SS low until EOF */
out_be32(&psc->sicr, sicr); out_be32(psc_addr(mps, sicr), sicr);
ccr = in_be32(&psc->ccr); ccr = in_be32(psc_addr(mps, ccr));
ccr &= 0xFF000000; ccr &= 0xFF000000;
speed = 1000000; /* default 1MHz */ speed = 1000000; /* default 1MHz */
bclkdiv = (mps->mclk_rate / speed) - 1; bclkdiv = (mps->mclk_rate / speed) - 1;
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
out_be32(&psc->ccr, ccr); out_be32(psc_addr(mps, ccr), ccr);
/* Set 2ms DTL delay */ /* Set 2ms DTL delay */
out_8(&psc->ctur, 0x00); out_8(psc_addr(mps, ctur), 0x00);
out_8(&psc->ctlr, 0x82); out_8(psc_addr(mps, ctlr), 0x82);
/* we don't use the alarms */ /* we don't use the alarms */
out_be32(&fifo->rxalarm, 0xfff); out_be32(&fifo->rxalarm, 0xfff);
...@@ -482,6 +504,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, ...@@ -482,6 +504,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
dev_set_drvdata(dev, master); dev_set_drvdata(dev, master);
mps = spi_master_get_devdata(master); mps = spi_master_get_devdata(master);
mps->type = (int)of_device_get_match_data(dev);
mps->irq = irq; mps->irq = irq;
if (pdata == NULL) { if (pdata == NULL) {
...@@ -589,7 +612,8 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op) ...@@ -589,7 +612,8 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op)
} }
static const struct of_device_id mpc512x_psc_spi_of_match[] = { static const struct of_device_id mpc512x_psc_spi_of_match[] = {
{ .compatible = "fsl,mpc5121-psc-spi", }, { .compatible = "fsl,mpc5121-psc-spi", .data = (void *)TYPE_MPC5121 },
{ .compatible = "fsl,mpc5125-psc-spi", .data = (void *)TYPE_MPC5125 },
{}, {},
}; };
......
/*
* Copyright (c) 2015 MediaTek Inc.
* Author: Leilk Liu <leilk.liu@mediatek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/platform_data/spi-mt65xx.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#define SPI_CFG0_REG 0x0000
#define SPI_CFG1_REG 0x0004
#define SPI_TX_SRC_REG 0x0008
#define SPI_RX_DST_REG 0x000c
#define SPI_TX_DATA_REG 0x0010
#define SPI_RX_DATA_REG 0x0014
#define SPI_CMD_REG 0x0018
#define SPI_STATUS0_REG 0x001c
#define SPI_PAD_SEL_REG 0x0024
#define SPI_CFG0_SCK_HIGH_OFFSET 0
#define SPI_CFG0_SCK_LOW_OFFSET 8
#define SPI_CFG0_CS_HOLD_OFFSET 16
#define SPI_CFG0_CS_SETUP_OFFSET 24
#define SPI_CFG1_CS_IDLE_OFFSET 0
#define SPI_CFG1_PACKET_LOOP_OFFSET 8
#define SPI_CFG1_PACKET_LENGTH_OFFSET 16
#define SPI_CFG1_GET_TICK_DLY_OFFSET 30
#define SPI_CFG1_CS_IDLE_MASK 0xff
#define SPI_CFG1_PACKET_LOOP_MASK 0xff00
#define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000
#define SPI_CMD_ACT BIT(0)
#define SPI_CMD_RESUME BIT(1)
#define SPI_CMD_RST BIT(2)
#define SPI_CMD_PAUSE_EN BIT(4)
#define SPI_CMD_DEASSERT BIT(5)
#define SPI_CMD_CPHA BIT(8)
#define SPI_CMD_CPOL BIT(9)
#define SPI_CMD_RX_DMA BIT(10)
#define SPI_CMD_TX_DMA BIT(11)
#define SPI_CMD_TXMSBF BIT(12)
#define SPI_CMD_RXMSBF BIT(13)
#define SPI_CMD_RX_ENDIAN BIT(14)
#define SPI_CMD_TX_ENDIAN BIT(15)
#define SPI_CMD_FINISH_IE BIT(16)
#define SPI_CMD_PAUSE_IE BIT(17)
#define MT8173_SPI_MAX_PAD_SEL 3
#define MTK_SPI_PAUSE_INT_STATUS 0x2
#define MTK_SPI_IDLE 0
#define MTK_SPI_PAUSED 1
#define MTK_SPI_MAX_FIFO_SIZE 32
#define MTK_SPI_PACKET_SIZE 1024
struct mtk_spi_compatible {
bool need_pad_sel;
/* Must explicitly send dummy Tx bytes to do Rx only transfer */
bool must_tx;
};
struct mtk_spi {
void __iomem *base;
u32 state;
u32 pad_sel;
struct clk *spi_clk, *parent_clk;
struct spi_transfer *cur_transfer;
u32 xfer_len;
struct scatterlist *tx_sgl, *rx_sgl;
u32 tx_sgl_len, rx_sgl_len;
const struct mtk_spi_compatible *dev_comp;
};
static const struct mtk_spi_compatible mt6589_compat;
static const struct mtk_spi_compatible mt8135_compat;
static const struct mtk_spi_compatible mt8173_compat = {
.need_pad_sel = true,
.must_tx = true,
};
/*
* A piece of default chip info unless the platform
* supplies it.
*/
static const struct mtk_chip_config mtk_default_chip_info = {
.rx_mlsb = 1,
.tx_mlsb = 1,
};
static const struct of_device_id mtk_spi_of_match[] = {
{ .compatible = "mediatek,mt6589-spi", .data = (void *)&mt6589_compat },
{ .compatible = "mediatek,mt8135-spi", .data = (void *)&mt8135_compat },
{ .compatible = "mediatek,mt8173-spi", .data = (void *)&mt8173_compat },
{}
};
MODULE_DEVICE_TABLE(of, mtk_spi_of_match);
static void mtk_spi_reset(struct mtk_spi *mdata)
{
u32 reg_val;
/* set the software reset bit in SPI_CMD_REG. */
reg_val = readl(mdata->base + SPI_CMD_REG);
reg_val |= SPI_CMD_RST;
writel(reg_val, mdata->base + SPI_CMD_REG);
reg_val = readl(mdata->base + SPI_CMD_REG);
reg_val &= ~SPI_CMD_RST;
writel(reg_val, mdata->base + SPI_CMD_REG);
}
static void mtk_spi_config(struct mtk_spi *mdata,
struct mtk_chip_config *chip_config)
{
u32 reg_val;
reg_val = readl(mdata->base + SPI_CMD_REG);
/* set the mlsbx and mlsbtx */
if (chip_config->tx_mlsb)
reg_val |= SPI_CMD_TXMSBF;
else
reg_val &= ~SPI_CMD_TXMSBF;
if (chip_config->rx_mlsb)
reg_val |= SPI_CMD_RXMSBF;
else
reg_val &= ~SPI_CMD_RXMSBF;
/* set the tx/rx endian */
#ifdef __LITTLE_ENDIAN
reg_val &= ~SPI_CMD_TX_ENDIAN;
reg_val &= ~SPI_CMD_RX_ENDIAN;
#else
reg_val |= SPI_CMD_TX_ENDIAN;
reg_val |= SPI_CMD_RX_ENDIAN;
#endif
/* set finish and pause interrupt always enable */
reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_IE;
/* disable dma mode */
reg_val &= ~(SPI_CMD_TX_DMA | SPI_CMD_RX_DMA);
/* disable deassert mode */
reg_val &= ~SPI_CMD_DEASSERT;
writel(reg_val, mdata->base + SPI_CMD_REG);
/* pad select */
if (mdata->dev_comp->need_pad_sel)
writel(mdata->pad_sel, mdata->base + SPI_PAD_SEL_REG);
}
static int mtk_spi_prepare_hardware(struct spi_master *master)
{
struct spi_transfer *trans;
struct mtk_spi *mdata = spi_master_get_devdata(master);
struct spi_message *msg = master->cur_msg;
trans = list_first_entry(&msg->transfers, struct spi_transfer,
transfer_list);
if (!trans->cs_change) {
mdata->state = MTK_SPI_IDLE;
mtk_spi_reset(mdata);
}
return 0;
}
static int mtk_spi_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
u32 reg_val;
u8 cpha, cpol;
struct mtk_chip_config *chip_config;
struct spi_device *spi = msg->spi;
struct mtk_spi *mdata = spi_master_get_devdata(master);
cpha = spi->mode & SPI_CPHA ? 1 : 0;
cpol = spi->mode & SPI_CPOL ? 1 : 0;
reg_val = readl(mdata->base + SPI_CMD_REG);
if (cpha)
reg_val |= SPI_CMD_CPHA;
else
reg_val &= ~SPI_CMD_CPHA;
if (cpol)
reg_val |= SPI_CMD_CPOL;
else
reg_val &= ~SPI_CMD_CPOL;
writel(reg_val, mdata->base + SPI_CMD_REG);
chip_config = spi->controller_data;
if (!chip_config) {
chip_config = (void *)&mtk_default_chip_info;
spi->controller_data = chip_config;
}
mtk_spi_config(mdata, chip_config);
return 0;
}
static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
{
u32 reg_val;
struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
reg_val = readl(mdata->base + SPI_CMD_REG);
if (!enable)
reg_val |= SPI_CMD_PAUSE_EN;
else
reg_val &= ~SPI_CMD_PAUSE_EN;
writel(reg_val, mdata->base + SPI_CMD_REG);
}
static void mtk_spi_prepare_transfer(struct spi_master *master,
struct spi_transfer *xfer)
{
u32 spi_clk_hz, div, sck_time, cs_time, reg_val = 0;
struct mtk_spi *mdata = spi_master_get_devdata(master);
spi_clk_hz = clk_get_rate(mdata->spi_clk);
if (xfer->speed_hz < spi_clk_hz / 2)
div = DIV_ROUND_UP(spi_clk_hz, xfer->speed_hz);
else
div = 1;
sck_time = (div + 1) / 2;
cs_time = sck_time * 2;
reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_HIGH_OFFSET);
reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET);
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET);
writel(reg_val, mdata->base + SPI_CFG0_REG);
reg_val = readl(mdata->base + SPI_CFG1_REG);
reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
writel(reg_val, mdata->base + SPI_CFG1_REG);
}
static void mtk_spi_setup_packet(struct spi_master *master)
{
u32 packet_size, packet_loop, reg_val;
struct mtk_spi *mdata = spi_master_get_devdata(master);
packet_size = min_t(u32, mdata->xfer_len, MTK_SPI_PACKET_SIZE);
packet_loop = mdata->xfer_len / packet_size;
reg_val = readl(mdata->base + SPI_CFG1_REG);
reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK | SPI_CFG1_PACKET_LOOP_MASK);
reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET;
reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET;
writel(reg_val, mdata->base + SPI_CFG1_REG);
}
static void mtk_spi_enable_transfer(struct spi_master *master)
{
u32 cmd;
struct mtk_spi *mdata = spi_master_get_devdata(master);
cmd = readl(mdata->base + SPI_CMD_REG);
if (mdata->state == MTK_SPI_IDLE)
cmd |= SPI_CMD_ACT;
else
cmd |= SPI_CMD_RESUME;
writel(cmd, mdata->base + SPI_CMD_REG);
}
static int mtk_spi_get_mult_delta(u32 xfer_len)
{
u32 mult_delta;
if (xfer_len > MTK_SPI_PACKET_SIZE)
mult_delta = xfer_len % MTK_SPI_PACKET_SIZE;
else
mult_delta = 0;
return mult_delta;
}
static void mtk_spi_update_mdata_len(struct spi_master *master)
{
int mult_delta;
struct mtk_spi *mdata = spi_master_get_devdata(master);
if (mdata->tx_sgl_len && mdata->rx_sgl_len) {
if (mdata->tx_sgl_len > mdata->rx_sgl_len) {
mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len);
mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
mdata->rx_sgl_len = mult_delta;
mdata->tx_sgl_len -= mdata->xfer_len;
} else {
mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len);
mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
mdata->tx_sgl_len = mult_delta;
mdata->rx_sgl_len -= mdata->xfer_len;
}
} else if (mdata->tx_sgl_len) {
mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len);
mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
mdata->tx_sgl_len = mult_delta;
} else if (mdata->rx_sgl_len) {
mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len);
mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
mdata->rx_sgl_len = mult_delta;
}
}
static void mtk_spi_setup_dma_addr(struct spi_master *master,
struct spi_transfer *xfer)
{
struct mtk_spi *mdata = spi_master_get_devdata(master);
if (mdata->tx_sgl)
writel(xfer->tx_dma, mdata->base + SPI_TX_SRC_REG);
if (mdata->rx_sgl)
writel(xfer->rx_dma, mdata->base + SPI_RX_DST_REG);
}
static int mtk_spi_fifo_transfer(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
int cnt;
struct mtk_spi *mdata = spi_master_get_devdata(master);
mdata->cur_transfer = xfer;
mdata->xfer_len = xfer->len;
mtk_spi_prepare_transfer(master, xfer);
mtk_spi_setup_packet(master);
if (xfer->len % 4)
cnt = xfer->len / 4 + 1;
else
cnt = xfer->len / 4;
iowrite32_rep(mdata->base + SPI_TX_DATA_REG, xfer->tx_buf, cnt);
mtk_spi_enable_transfer(master);
return 1;
}
static int mtk_spi_dma_transfer(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
int cmd;
struct mtk_spi *mdata = spi_master_get_devdata(master);
mdata->tx_sgl = NULL;
mdata->rx_sgl = NULL;
mdata->tx_sgl_len = 0;
mdata->rx_sgl_len = 0;
mdata->cur_transfer = xfer;
mtk_spi_prepare_transfer(master, xfer);
cmd = readl(mdata->base + SPI_CMD_REG);
if (xfer->tx_buf)
cmd |= SPI_CMD_TX_DMA;
if (xfer->rx_buf)
cmd |= SPI_CMD_RX_DMA;
writel(cmd, mdata->base + SPI_CMD_REG);
if (xfer->tx_buf)
mdata->tx_sgl = xfer->tx_sg.sgl;
if (xfer->rx_buf)
mdata->rx_sgl = xfer->rx_sg.sgl;
if (mdata->tx_sgl) {
xfer->tx_dma = sg_dma_address(mdata->tx_sgl);
mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
}
if (mdata->rx_sgl) {
xfer->rx_dma = sg_dma_address(mdata->rx_sgl);
mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
}
mtk_spi_update_mdata_len(master);
mtk_spi_setup_packet(master);
mtk_spi_setup_dma_addr(master, xfer);
mtk_spi_enable_transfer(master);
return 1;
}
static int mtk_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
if (master->can_dma(master, spi, xfer))
return mtk_spi_dma_transfer(master, spi, xfer);
else
return mtk_spi_fifo_transfer(master, spi, xfer);
}
static bool mtk_spi_can_dma(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
return xfer->len > MTK_SPI_MAX_FIFO_SIZE;
}
static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
{
u32 cmd, reg_val, cnt;
struct spi_master *master = dev_id;
struct mtk_spi *mdata = spi_master_get_devdata(master);
struct spi_transfer *trans = mdata->cur_transfer;
reg_val = readl(mdata->base + SPI_STATUS0_REG);
if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
mdata->state = MTK_SPI_PAUSED;
else
mdata->state = MTK_SPI_IDLE;
if (!master->can_dma(master, master->cur_msg->spi, trans)) {
if (trans->rx_buf) {
if (mdata->xfer_len % 4)
cnt = mdata->xfer_len / 4 + 1;
else
cnt = mdata->xfer_len / 4;
ioread32_rep(mdata->base + SPI_RX_DATA_REG,
trans->rx_buf, cnt);
}
spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
if (mdata->tx_sgl)
trans->tx_dma += mdata->xfer_len;
if (mdata->rx_sgl)
trans->rx_dma += mdata->xfer_len;
if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) {
mdata->tx_sgl = sg_next(mdata->tx_sgl);
if (mdata->tx_sgl) {
trans->tx_dma = sg_dma_address(mdata->tx_sgl);
mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
}
}
if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) {
mdata->rx_sgl = sg_next(mdata->rx_sgl);
if (mdata->rx_sgl) {
trans->rx_dma = sg_dma_address(mdata->rx_sgl);
mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
}
}
if (!mdata->tx_sgl && !mdata->rx_sgl) {
/* spi disable dma */
cmd = readl(mdata->base + SPI_CMD_REG);
cmd &= ~SPI_CMD_TX_DMA;
cmd &= ~SPI_CMD_RX_DMA;
writel(cmd, mdata->base + SPI_CMD_REG);
spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
mtk_spi_update_mdata_len(master);
mtk_spi_setup_packet(master);
mtk_spi_setup_dma_addr(master, trans);
mtk_spi_enable_transfer(master);
return IRQ_HANDLED;
}
static int mtk_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct mtk_spi *mdata;
const struct of_device_id *of_id;
struct resource *res;
int irq, ret;
master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
if (!master) {
dev_err(&pdev->dev, "failed to alloc spi master\n");
return -ENOMEM;
}
master->auto_runtime_pm = true;
master->dev.of_node = pdev->dev.of_node;
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->set_cs = mtk_spi_set_cs;
master->prepare_transfer_hardware = mtk_spi_prepare_hardware;
master->prepare_message = mtk_spi_prepare_message;
master->transfer_one = mtk_spi_transfer_one;
master->can_dma = mtk_spi_can_dma;
of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node);
if (!of_id) {
dev_err(&pdev->dev, "failed to probe of_node\n");
ret = -EINVAL;
goto err_put_master;
}
mdata = spi_master_get_devdata(master);
mdata->dev_comp = of_id->data;
if (mdata->dev_comp->must_tx)
master->flags = SPI_MASTER_MUST_TX;
if (mdata->dev_comp->need_pad_sel) {
ret = of_property_read_u32(pdev->dev.of_node,
"mediatek,pad-select",
&mdata->pad_sel);
if (ret) {
dev_err(&pdev->dev, "failed to read pad select: %d\n",
ret);
goto err_put_master;
}
if (mdata->pad_sel > MT8173_SPI_MAX_PAD_SEL) {
dev_err(&pdev->dev, "wrong pad-select: %u\n",
mdata->pad_sel);
ret = -EINVAL;
goto err_put_master;
}
}
platform_set_drvdata(pdev, master);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
dev_err(&pdev->dev, "failed to determine base address\n");
goto err_put_master;
}
mdata->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(mdata->base)) {
ret = PTR_ERR(mdata->base);
goto err_put_master;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get irq (%d)\n", irq);
ret = irq;
goto err_put_master;
}
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
ret = devm_request_irq(&pdev->dev, irq, mtk_spi_interrupt,
IRQF_TRIGGER_NONE, dev_name(&pdev->dev), master);
if (ret) {
dev_err(&pdev->dev, "failed to register irq (%d)\n", ret);
goto err_put_master;
}
mdata->spi_clk = devm_clk_get(&pdev->dev, "spi-clk");
if (IS_ERR(mdata->spi_clk)) {
ret = PTR_ERR(mdata->spi_clk);
dev_err(&pdev->dev, "failed to get spi-clk: %d\n", ret);
goto err_put_master;
}
mdata->parent_clk = devm_clk_get(&pdev->dev, "parent-clk");
if (IS_ERR(mdata->parent_clk)) {
ret = PTR_ERR(mdata->parent_clk);
dev_err(&pdev->dev, "failed to get parent-clk: %d\n", ret);
goto err_put_master;
}
ret = clk_prepare_enable(mdata->spi_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret);
goto err_put_master;
}
ret = clk_set_parent(mdata->spi_clk, mdata->parent_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to clk_set_parent (%d)\n", ret);
goto err_disable_clk;
}
clk_disable_unprepare(mdata->spi_clk);
pm_runtime_enable(&pdev->dev);
ret = devm_spi_register_master(&pdev->dev, master);
if (ret) {
dev_err(&pdev->dev, "failed to register master (%d)\n", ret);
goto err_put_master;
}
return 0;
err_disable_clk:
clk_disable_unprepare(mdata->spi_clk);
err_put_master:
spi_master_put(master);
return ret;
}
static int mtk_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
pm_runtime_disable(&pdev->dev);
mtk_spi_reset(mdata);
clk_disable_unprepare(mdata->spi_clk);
spi_master_put(master);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int mtk_spi_suspend(struct device *dev)
{
int ret;
struct spi_master *master = dev_get_drvdata(dev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
ret = spi_master_suspend(master);
if (ret)
return ret;
if (!pm_runtime_suspended(dev))
clk_disable_unprepare(mdata->spi_clk);
return ret;
}
static int mtk_spi_resume(struct device *dev)
{
int ret;
struct spi_master *master = dev_get_drvdata(dev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
if (!pm_runtime_suspended(dev)) {
ret = clk_prepare_enable(mdata->spi_clk);
if (ret < 0) {
dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
return ret;
}
}
ret = spi_master_resume(master);
if (ret < 0)
clk_disable_unprepare(mdata->spi_clk);
return ret;
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int mtk_spi_runtime_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
clk_disable_unprepare(mdata->spi_clk);
return 0;
}
static int mtk_spi_runtime_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
int ret;
ret = clk_prepare_enable(mdata->spi_clk);
if (ret < 0) {
dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
return ret;
}
return 0;
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops mtk_spi_pm = {
SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_suspend, mtk_spi_resume)
SET_RUNTIME_PM_OPS(mtk_spi_runtime_suspend,
mtk_spi_runtime_resume, NULL)
};
static struct platform_driver mtk_spi_driver = {
.driver = {
.name = "mtk-spi",
.pm = &mtk_spi_pm,
.of_match_table = mtk_spi_of_match,
},
.probe = mtk_spi_probe,
.remove = mtk_spi_remove,
};
module_platform_driver(mtk_spi_driver);
MODULE_DESCRIPTION("MTK SPI Controller driver");
MODULE_AUTHOR("Leilk Liu <leilk.liu@mediatek.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:mtk-spi");
...@@ -245,6 +245,7 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) ...@@ -245,6 +245,7 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
{ {
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
u32 l; u32 l;
/* The controller handles the inverted chip selects /* The controller handles the inverted chip selects
...@@ -255,6 +256,12 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) ...@@ -255,6 +256,12 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
enable = !enable; enable = !enable;
if (spi->controller_state) { if (spi->controller_state) {
int err = pm_runtime_get_sync(mcspi->dev);
if (err < 0) {
dev_err(mcspi->dev, "failed to get sync: %d\n", err);
return;
}
l = mcspi_cached_chconf0(spi); l = mcspi_cached_chconf0(spi);
if (enable) if (enable)
...@@ -263,6 +270,9 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) ...@@ -263,6 +270,9 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
l |= OMAP2_MCSPI_CHCONF_FORCE; l |= OMAP2_MCSPI_CHCONF_FORCE;
mcspi_write_chconf0(spi, l); mcspi_write_chconf0(spi, l);
pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
} }
} }
......
...@@ -41,6 +41,11 @@ ...@@ -41,6 +41,11 @@
#define ORION_SPI_DATA_OUT_REG 0x08 #define ORION_SPI_DATA_OUT_REG 0x08
#define ORION_SPI_DATA_IN_REG 0x0c #define ORION_SPI_DATA_IN_REG 0x0c
#define ORION_SPI_INT_CAUSE_REG 0x10 #define ORION_SPI_INT_CAUSE_REG 0x10
#define ORION_SPI_TIMING_PARAMS_REG 0x18
#define ORION_SPI_TMISO_SAMPLE_MASK (0x3 << 6)
#define ORION_SPI_TMISO_SAMPLE_1 (1 << 6)
#define ORION_SPI_TMISO_SAMPLE_2 (2 << 6)
#define ORION_SPI_MODE_CPOL (1 << 11) #define ORION_SPI_MODE_CPOL (1 << 11)
#define ORION_SPI_MODE_CPHA (1 << 12) #define ORION_SPI_MODE_CPHA (1 << 12)
...@@ -70,6 +75,7 @@ struct orion_spi_dev { ...@@ -70,6 +75,7 @@ struct orion_spi_dev {
unsigned int min_divisor; unsigned int min_divisor;
unsigned int max_divisor; unsigned int max_divisor;
u32 prescale_mask; u32 prescale_mask;
bool is_errata_50mhz_ac;
}; };
struct orion_spi { struct orion_spi {
...@@ -195,6 +201,41 @@ orion_spi_mode_set(struct spi_device *spi) ...@@ -195,6 +201,41 @@ orion_spi_mode_set(struct spi_device *spi)
writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
} }
static void
orion_spi_50mhz_ac_timing_erratum(struct spi_device *spi, unsigned int speed)
{
u32 reg;
struct orion_spi *orion_spi;
orion_spi = spi_master_get_devdata(spi->master);
/*
* Erratum description: (Erratum NO. FE-9144572) The device
* SPI interface supports frequencies of up to 50 MHz.
* However, due to this erratum, when the device core clock is
* 250 MHz and the SPI interfaces is configured for 50MHz SPI
* clock and CPOL=CPHA=1 there might occur data corruption on
* reads from the SPI device.
* Erratum Workaround:
* Work in one of the following configurations:
* 1. Set CPOL=CPHA=0 in "SPI Interface Configuration
* Register".
* 2. Set TMISO_SAMPLE value to 0x2 in "SPI Timing Parameters 1
* Register" before setting the interface.
*/
reg = readl(spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
reg &= ~ORION_SPI_TMISO_SAMPLE_MASK;
if (clk_get_rate(orion_spi->clk) == 250000000 &&
speed == 50000000 && spi->mode & SPI_CPOL &&
spi->mode & SPI_CPHA)
reg |= ORION_SPI_TMISO_SAMPLE_2;
else
reg |= ORION_SPI_TMISO_SAMPLE_1; /* This is the default value */
writel(reg, spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
}
/* /*
* called only when no transfer is active on the bus * called only when no transfer is active on the bus
*/ */
...@@ -216,6 +257,9 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -216,6 +257,9 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
orion_spi_mode_set(spi); orion_spi_mode_set(spi);
if (orion_spi->devdata->is_errata_50mhz_ac)
orion_spi_50mhz_ac_timing_erratum(spi, speed);
rc = orion_spi_baudrate_set(spi, speed); rc = orion_spi_baudrate_set(spi, speed);
if (rc) if (rc)
return rc; return rc;
...@@ -413,6 +457,14 @@ static const struct orion_spi_dev armada_375_spi_dev_data = { ...@@ -413,6 +457,14 @@ static const struct orion_spi_dev armada_375_spi_dev_data = {
.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK, .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
}; };
static const struct orion_spi_dev armada_380_spi_dev_data = {
.typ = ARMADA_SPI,
.max_hz = 50000000,
.max_divisor = 1920,
.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
.is_errata_50mhz_ac = true,
};
static const struct of_device_id orion_spi_of_match_table[] = { static const struct of_device_id orion_spi_of_match_table[] = {
{ {
.compatible = "marvell,orion-spi", .compatible = "marvell,orion-spi",
...@@ -428,7 +480,7 @@ static const struct of_device_id orion_spi_of_match_table[] = { ...@@ -428,7 +480,7 @@ static const struct of_device_id orion_spi_of_match_table[] = {
}, },
{ {
.compatible = "marvell,armada-380-spi", .compatible = "marvell,armada-380-spi",
.data = &armada_xp_spi_dev_data, .data = &armada_380_spi_dev_data,
}, },
{ {
.compatible = "marvell,armada-390-spi", .compatible = "marvell,armada-390-spi",
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/clk.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
...@@ -97,6 +98,15 @@ static const struct lpss_config lpss_platforms[] = { ...@@ -97,6 +98,15 @@ static const struct lpss_config lpss_platforms[] = {
.tx_threshold_lo = 160, .tx_threshold_lo = 160,
.tx_threshold_hi = 224, .tx_threshold_hi = 224,
}, },
{ /* LPSS_SPT_SSP */
.offset = 0x200,
.reg_general = -1,
.reg_ssp = 0x20,
.reg_cs_ctrl = 0x24,
.rx_threshold = 1,
.tx_threshold_lo = 32,
.tx_threshold_hi = 56,
},
}; };
static inline const struct lpss_config static inline const struct lpss_config
...@@ -110,6 +120,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data) ...@@ -110,6 +120,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data)
switch (drv_data->ssp_type) { switch (drv_data->ssp_type) {
case LPSS_LPT_SSP: case LPSS_LPT_SSP:
case LPSS_BYT_SSP: case LPSS_BYT_SSP:
case LPSS_SPT_SSP:
return true; return true;
default: default:
return false; return false;
...@@ -1107,6 +1118,7 @@ static int setup(struct spi_device *spi) ...@@ -1107,6 +1118,7 @@ static int setup(struct spi_device *spi)
break; break;
case LPSS_LPT_SSP: case LPSS_LPT_SSP:
case LPSS_BYT_SSP: case LPSS_BYT_SSP:
case LPSS_SPT_SSP:
config = lpss_get_config(drv_data); config = lpss_get_config(drv_data);
tx_thres = config->tx_threshold_lo; tx_thres = config->tx_threshold_lo;
tx_hi_thres = config->tx_threshold_hi; tx_hi_thres = config->tx_threshold_hi;
...@@ -1276,6 +1288,31 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { ...@@ -1276,6 +1288,31 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
}; };
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
/*
* PCI IDs of compound devices that integrate both host controller and private
* integrated DMA engine. Please note these are not used in module
* autoloading and probing in this module but matching the LPSS SSP type.
*/
static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
/* SPT-LP */
{ PCI_VDEVICE(INTEL, 0x9d29), LPSS_SPT_SSP },
{ PCI_VDEVICE(INTEL, 0x9d2a), LPSS_SPT_SSP },
/* SPT-H */
{ PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP },
{ PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP },
{ },
};
static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
{
struct device *dev = param;
if (dev != chan->device->dev->parent)
return false;
return true;
}
static struct pxa2xx_spi_master * static struct pxa2xx_spi_master *
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
{ {
...@@ -1283,16 +1320,25 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) ...@@ -1283,16 +1320,25 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
struct acpi_device *adev; struct acpi_device *adev;
struct ssp_device *ssp; struct ssp_device *ssp;
struct resource *res; struct resource *res;
const struct acpi_device_id *id; const struct acpi_device_id *adev_id = NULL;
const struct pci_device_id *pcidev_id = NULL;
int devid, type; int devid, type;
if (!ACPI_HANDLE(&pdev->dev) || if (!ACPI_HANDLE(&pdev->dev) ||
acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev)) acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
return NULL; return NULL;
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); if (dev_is_pci(pdev->dev.parent))
if (id) pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match,
type = (int)id->driver_data; to_pci_dev(pdev->dev.parent));
else
adev_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
&pdev->dev);
if (adev_id)
type = (int)adev_id->driver_data;
else if (pcidev_id)
type = (int)pcidev_id->driver_data;
else else
return NULL; return NULL;
...@@ -1311,6 +1357,12 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) ...@@ -1311,6 +1357,12 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
if (IS_ERR(ssp->mmio_base)) if (IS_ERR(ssp->mmio_base))
return NULL; return NULL;
if (pcidev_id) {
pdata->tx_param = pdev->dev.parent;
pdata->rx_param = pdev->dev.parent;
pdata->dma_filter = pxa2xx_spi_idma_filter;
}
ssp->clk = devm_clk_get(&pdev->dev, NULL); ssp->clk = devm_clk_get(&pdev->dev, NULL);
ssp->irq = platform_get_irq(pdev, 0); ssp->irq = platform_get_irq(pdev, 0);
ssp->type = type; ssp->type = type;
...@@ -1362,8 +1414,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1362,8 +1414,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
/* Allocate master with space for drv_data and null dma buffer */ master = spi_alloc_master(dev, sizeof(struct driver_data));
master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
if (!master) { if (!master) {
dev_err(&pdev->dev, "cannot alloc spi_master\n"); dev_err(&pdev->dev, "cannot alloc spi_master\n");
pxa_ssp_free(ssp); pxa_ssp_free(ssp);
...@@ -1390,7 +1441,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1390,7 +1441,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
drv_data->ssp_type = ssp->type; drv_data->ssp_type = ssp->type;
drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
drv_data->ioaddr = ssp->mmio_base; drv_data->ioaddr = ssp->mmio_base;
drv_data->ssdr_physical = ssp->phys_base + SSDR; drv_data->ssdr_physical = ssp->phys_base + SSDR;
...@@ -1424,8 +1474,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1424,8 +1474,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
} }
/* Setup DMA if requested */ /* Setup DMA if requested */
drv_data->tx_channel = -1;
drv_data->rx_channel = -1;
if (platform_info->enable_dma) { if (platform_info->enable_dma) {
status = pxa2xx_spi_dma_setup(drv_data); status = pxa2xx_spi_dma_setup(drv_data);
if (status) { if (status) {
......
...@@ -36,11 +36,6 @@ struct driver_data { ...@@ -36,11 +36,6 @@ struct driver_data {
/* PXA hookup */ /* PXA hookup */
struct pxa2xx_spi_master *master_info; struct pxa2xx_spi_master *master_info;
/* PXA private DMA setup stuff */
int rx_channel;
int tx_channel;
u32 *null_dma_buf;
/* SSP register addresses */ /* SSP register addresses */
void __iomem *ioaddr; void __iomem *ioaddr;
u32 ssdr_physical; u32 ssdr_physical;
......
...@@ -645,7 +645,6 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -645,7 +645,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
rs = spi_master_get_devdata(master); rs = spi_master_get_devdata(master);
memset(rs, 0, sizeof(struct rockchip_spi));
/* Get basic io resource and map it */ /* Get basic io resource and map it */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......
...@@ -383,7 +383,8 @@ static void qspi_update(const struct rspi_data *rspi, u8 mask, u8 val, u8 reg) ...@@ -383,7 +383,8 @@ static void qspi_update(const struct rspi_data *rspi, u8 mask, u8 val, u8 reg)
rspi_write8(rspi, data, reg); rspi_write8(rspi, data, reg);
} }
static int qspi_set_send_trigger(struct rspi_data *rspi, unsigned int len) static unsigned int qspi_set_send_trigger(struct rspi_data *rspi,
unsigned int len)
{ {
unsigned int n; unsigned int n;
...@@ -724,25 +725,25 @@ static int rspi_rz_transfer_one(struct spi_master *master, ...@@ -724,25 +725,25 @@ static int rspi_rz_transfer_one(struct spi_master *master,
static int qspi_trigger_transfer_out_in(struct rspi_data *rspi, const u8 *tx, static int qspi_trigger_transfer_out_in(struct rspi_data *rspi, const u8 *tx,
u8 *rx, unsigned int len) u8 *rx, unsigned int len)
{ {
int i, n, ret; unsigned int i, n;
int error; int ret;
while (len > 0) { while (len > 0) {
n = qspi_set_send_trigger(rspi, len); n = qspi_set_send_trigger(rspi, len);
qspi_set_receive_trigger(rspi, len); qspi_set_receive_trigger(rspi, len);
if (n == QSPI_BUFFER_SIZE) { if (n == QSPI_BUFFER_SIZE) {
error = rspi_wait_for_tx_empty(rspi); ret = rspi_wait_for_tx_empty(rspi);
if (error < 0) { if (ret < 0) {
dev_err(&rspi->master->dev, "transmit timeout\n"); dev_err(&rspi->master->dev, "transmit timeout\n");
return error; return ret;
} }
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
rspi_write_data(rspi, *tx++); rspi_write_data(rspi, *tx++);
error = rspi_wait_for_rx_full(rspi); ret = rspi_wait_for_rx_full(rspi);
if (error < 0) { if (ret < 0) {
dev_err(&rspi->master->dev, "receive timeout\n"); dev_err(&rspi->master->dev, "receive timeout\n");
return error; return ret;
} }
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
*rx++ = rspi_read_data(rspi); *rx++ = rspi_read_data(rspi);
......
...@@ -501,7 +501,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) ...@@ -501,7 +501,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
} }
hw = spi_master_get_devdata(master); hw = spi_master_get_devdata(master);
memset(hw, 0, sizeof(struct s3c24xx_spi));
hw->master = master; hw->master = master;
hw->pdata = pdata = dev_get_platdata(&pdev->dev); hw->pdata = pdata = dev_get_platdata(&pdev->dev);
......
...@@ -1191,8 +1191,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1191,8 +1191,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n", dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
sdd->port_id, master->num_chipselect); sdd->port_id, master->num_chipselect);
dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tDMA=[Rx-%d, Tx-%d]\n", dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\tDMA=[Rx-%d, Tx-%d]\n",
mem_res, mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1,
sdd->rx_dma.dmach, sdd->tx_dma.dmach); sdd->rx_dma.dmach, sdd->tx_dma.dmach);
return 0; return 0;
......
...@@ -48,8 +48,8 @@ struct sh_msiof_spi_priv { ...@@ -48,8 +48,8 @@ struct sh_msiof_spi_priv {
const struct sh_msiof_chipdata *chipdata; const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info; struct sh_msiof_spi_info *info;
struct completion done; struct completion done;
int tx_fifo_size; unsigned int tx_fifo_size;
int rx_fifo_size; unsigned int rx_fifo_size;
void *tx_dma_page; void *tx_dma_page;
void *rx_dma_page; void *rx_dma_page;
dma_addr_t tx_dma_addr; dma_addr_t tx_dma_addr;
...@@ -95,8 +95,6 @@ struct sh_msiof_spi_priv { ...@@ -95,8 +95,6 @@ struct sh_msiof_spi_priv {
#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ #define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */
#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */ #define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */
#define MAX_WDLEN 256U
/* TSCR and RSCR */ /* TSCR and RSCR */
#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */ #define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */
#define SCR_BRPS(i) (((i) - 1) << 8) #define SCR_BRPS(i) (((i) - 1) << 8)
...@@ -850,7 +848,12 @@ static int sh_msiof_transfer_one(struct spi_master *master, ...@@ -850,7 +848,12 @@ static int sh_msiof_transfer_one(struct spi_master *master,
* DMA supports 32-bit words only, hence pack 8-bit and 16-bit * DMA supports 32-bit words only, hence pack 8-bit and 16-bit
* words, with byte resp. word swapping. * words, with byte resp. word swapping.
*/ */
unsigned int l = min(len, MAX_WDLEN * 4); unsigned int l = 0;
if (tx_buf)
l = min(len, p->tx_fifo_size * 4);
if (rx_buf)
l = min(len, p->rx_fifo_size * 4);
if (bits <= 8) { if (bits <= 8) {
if (l & 3) if (l & 3)
...@@ -963,7 +966,7 @@ static const struct sh_msiof_chipdata sh_data = { ...@@ -963,7 +966,7 @@ static const struct sh_msiof_chipdata sh_data = {
static const struct sh_msiof_chipdata r8a779x_data = { static const struct sh_msiof_chipdata r8a779x_data = {
.tx_fifo_size = 64, .tx_fifo_size = 64,
.rx_fifo_size = 256, .rx_fifo_size = 64,
.master_flags = SPI_MASTER_MUST_TX, .master_flags = SPI_MASTER_MUST_TX,
}; };
...@@ -1265,11 +1268,6 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) ...@@ -1265,11 +1268,6 @@ static int sh_msiof_spi_remove(struct platform_device *pdev)
static const struct platform_device_id spi_driver_ids[] = { static const struct platform_device_id spi_driver_ids[] = {
{ "spi_sh_msiof", (kernel_ulong_t)&sh_data }, { "spi_sh_msiof", (kernel_ulong_t)&sh_data },
{ "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7792_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7793_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7794_msiof", (kernel_ulong_t)&r8a779x_data },
{}, {},
}; };
MODULE_DEVICE_TABLE(platform, spi_driver_ids); MODULE_DEVICE_TABLE(platform, spi_driver_ids);
......
...@@ -99,6 +99,8 @@ struct ti_qspi { ...@@ -99,6 +99,8 @@ struct ti_qspi {
#define QSPI_INVAL (4 << 16) #define QSPI_INVAL (4 << 16)
#define QSPI_WC_CMD_INT_EN (1 << 14) #define QSPI_WC_CMD_INT_EN (1 << 14)
#define QSPI_FLEN(n) ((n - 1) << 0) #define QSPI_FLEN(n) ((n - 1) << 0)
#define QSPI_WLEN_MAX_BITS 128
#define QSPI_WLEN_MAX_BYTES 16
/* STATUS REGISTER */ /* STATUS REGISTER */
#define BUSY 0x01 #define BUSY 0x01
...@@ -217,14 +219,16 @@ static inline u32 qspi_is_busy(struct ti_qspi *qspi) ...@@ -217,14 +219,16 @@ static inline u32 qspi_is_busy(struct ti_qspi *qspi)
static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
{ {
int wlen, count; int wlen, count, xfer_len;
unsigned int cmd; unsigned int cmd;
const u8 *txbuf; const u8 *txbuf;
u32 data;
txbuf = t->tx_buf; txbuf = t->tx_buf;
cmd = qspi->cmd | QSPI_WR_SNGL; cmd = qspi->cmd | QSPI_WR_SNGL;
count = t->len; count = t->len;
wlen = t->bits_per_word >> 3; /* in bytes */ wlen = t->bits_per_word >> 3; /* in bytes */
xfer_len = wlen;
while (count) { while (count) {
if (qspi_is_busy(qspi)) if (qspi_is_busy(qspi))
...@@ -234,7 +238,29 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) ...@@ -234,7 +238,29 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
case 1: case 1:
dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
cmd, qspi->dc, *txbuf); cmd, qspi->dc, *txbuf);
writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); if (count >= QSPI_WLEN_MAX_BYTES) {
u32 *txp = (u32 *)txbuf;
data = cpu_to_be32(*txp++);
writel(data, qspi->base +
QSPI_SPI_DATA_REG_3);
data = cpu_to_be32(*txp++);
writel(data, qspi->base +
QSPI_SPI_DATA_REG_2);
data = cpu_to_be32(*txp++);
writel(data, qspi->base +
QSPI_SPI_DATA_REG_1);
data = cpu_to_be32(*txp++);
writel(data, qspi->base +
QSPI_SPI_DATA_REG);
xfer_len = QSPI_WLEN_MAX_BYTES;
cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS);
} else {
writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG);
cmd = qspi->cmd | QSPI_WR_SNGL;
xfer_len = wlen;
cmd |= QSPI_WLEN(wlen);
}
break; break;
case 2: case 2:
dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n",
...@@ -254,8 +280,8 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) ...@@ -254,8 +280,8 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
dev_err(qspi->dev, "write timed out\n"); dev_err(qspi->dev, "write timed out\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
txbuf += wlen; txbuf += xfer_len;
count -= wlen; count -= xfer_len;
} }
return 0; return 0;
......
...@@ -237,11 +237,11 @@ static const struct i2c_device_id spi_xcomm_ids[] = { ...@@ -237,11 +237,11 @@ static const struct i2c_device_id spi_xcomm_ids[] = {
{ "spi-xcomm" }, { "spi-xcomm" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(i2c, spi_xcomm_ids);
static struct i2c_driver spi_xcomm_driver = { static struct i2c_driver spi_xcomm_driver = {
.driver = { .driver = {
.name = "spi-xcomm", .name = "spi-xcomm",
.owner = THIS_MODULE,
}, },
.id_table = spi_xcomm_ids, .id_table = spi_xcomm_ids,
.probe = spi_xcomm_probe, .probe = spi_xcomm_probe,
......
...@@ -249,19 +249,23 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ...@@ -249,19 +249,23 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
xspi->tx_ptr = t->tx_buf; xspi->tx_ptr = t->tx_buf;
xspi->rx_ptr = t->rx_buf; xspi->rx_ptr = t->rx_buf;
remaining_words = t->len / xspi->bytes_per_word; remaining_words = t->len / xspi->bytes_per_word;
reinit_completion(&xspi->done);
if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) { if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) {
u32 isr;
use_irq = true; use_irq = true;
xspi->write_fn(XSPI_INTR_TX_EMPTY,
xspi->regs + XIPIF_V123B_IISR_OFFSET);
/* Enable the global IPIF interrupt */
xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
xspi->regs + XIPIF_V123B_DGIER_OFFSET);
/* Inhibit irq to avoid spurious irqs on tx_empty*/ /* Inhibit irq to avoid spurious irqs on tx_empty*/
cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
xspi->regs + XSPI_CR_OFFSET); xspi->regs + XSPI_CR_OFFSET);
/* ACK old irqs (if any) */
isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
if (isr)
xspi->write_fn(isr,
xspi->regs + XIPIF_V123B_IISR_OFFSET);
/* Enable the global IPIF interrupt */
xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
xspi->regs + XIPIF_V123B_DGIER_OFFSET);
reinit_completion(&xspi->done);
} }
while (remaining_words) { while (remaining_words) {
...@@ -302,8 +306,10 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ...@@ -302,8 +306,10 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
remaining_words -= n_words; remaining_words -= n_words;
} }
if (use_irq) if (use_irq) {
xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET); xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
}
return t->len; return t->len;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment