mirror of https://gitee.com/openkylin/linux.git
Merge remote-tracking branches 'spi/topic/dw', 'spi/topic/fsl-espi', 'spi/topic/img-spfi' and 'spi/topic/mpc512x-psc' into spi-next
This commit is contained in:
commit
18c558ec74
|
@ -6,14 +6,14 @@ PSC in UART mode
|
|||
For PSC in UART mode the needed PSC serial devices
|
||||
are specified by fsl,mpc5121-psc-uart nodes in the
|
||||
fsl,mpc5121-immr SoC node. Additionally the PSC FIFO
|
||||
Controller node fsl,mpc5121-psc-fifo is requered there:
|
||||
Controller node fsl,mpc5121-psc-fifo is required there:
|
||||
|
||||
fsl,mpc5121-psc-uart nodes
|
||||
fsl,mpc512x-psc-uart nodes
|
||||
--------------------------
|
||||
|
||||
Required properties :
|
||||
- compatible : Should contain "fsl,mpc5121-psc-uart" and "fsl,mpc5121-psc"
|
||||
- cell-index : Index of the PSC in hardware
|
||||
- compatible : Should contain "fsl,<soc>-psc-uart" and "fsl,<soc>-psc"
|
||||
Supported <soc>s: mpc5121, mpc5125
|
||||
- reg : Offset and length of the register set for the PSC device
|
||||
- interrupts : <a b> where a is the interrupt number of the
|
||||
PSC FIFO Controller and b is a field that represents an
|
||||
|
@ -25,12 +25,21 @@ Recommended properties :
|
|||
- fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4)
|
||||
- fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4)
|
||||
|
||||
PSC in SPI mode
|
||||
---------------
|
||||
|
||||
fsl,mpc5121-psc-fifo node
|
||||
Similar to the UART mode a PSC can be operated in SPI mode. The compatible used
|
||||
for that is fsl,mpc5121-psc-spi. It requires a fsl,mpc5121-psc-fifo as well.
|
||||
The required and recommended properties are identical to the
|
||||
fsl,mpc5121-psc-uart nodes, just use spi instead of uart in the compatible
|
||||
string.
|
||||
|
||||
fsl,mpc512x-psc-fifo node
|
||||
-------------------------
|
||||
|
||||
Required properties :
|
||||
- compatible : Should be "fsl,mpc5121-psc-fifo"
|
||||
- compatible : Should be "fsl,<soc>-psc-fifo"
|
||||
Supported <soc>s: mpc5121, mpc5125
|
||||
- reg : Offset and length of the register set for the PSC
|
||||
FIFO Controller
|
||||
- interrupts : <a b> where a is the interrupt number of the
|
||||
|
@ -39,6 +48,9 @@ Required properties :
|
|||
- interrupt-parent : the phandle for the interrupt controller that
|
||||
services interrupts for this device.
|
||||
|
||||
Recommended properties :
|
||||
- clocks : specifies the clock needed to operate the fifo controller
|
||||
- clock-names : name(s) for the clock(s) listed in clocks
|
||||
|
||||
Example for a board using PSC0 and PSC1 devices in serial mode:
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ Required properties:
|
|||
Optional properties:
|
||||
- cs-gpios : Specifies the gpio pis to be used for chipselects.
|
||||
- num-cs : The number of chipselects. If omitted, this will default to 4.
|
||||
- reg-io-width : The I/O register width (in bytes) implemented by this
|
||||
device. Supported values are 2 or 4 (the default).
|
||||
|
||||
Child nodes as per the generic SPI binding.
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ Required properties:
|
|||
Optional properties:
|
||||
- img,supports-quad-mode: Should be set if the interface supports quad mode
|
||||
SPI transfers.
|
||||
- spfi-max-frequency: Maximum speed supported by the spfi block.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -150,7 +150,10 @@
|
|||
|
||||
/* Structure of the hardware registers */
|
||||
struct mpc52xx_psc {
|
||||
u8 mode; /* PSC + 0x00 */
|
||||
union {
|
||||
u8 mode; /* PSC + 0x00 */
|
||||
u8 mr2;
|
||||
};
|
||||
u8 reserved0[3];
|
||||
union { /* PSC + 0x04 */
|
||||
u16 status;
|
||||
|
|
|
@ -74,6 +74,9 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
|
|||
|
||||
dws->max_freq = clk_get_rate(dwsmmio->clk);
|
||||
|
||||
of_property_read_u32(pdev->dev.of_node, "reg-io-width",
|
||||
&dws->reg_io_width);
|
||||
|
||||
num_cs = 4;
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
|
|
|
@ -194,7 +194,7 @@ static void dw_writer(struct dw_spi *dws)
|
|||
else
|
||||
txw = *(u16 *)(dws->tx);
|
||||
}
|
||||
dw_writel(dws, DW_SPI_DR, txw);
|
||||
dw_write_io_reg(dws, DW_SPI_DR, txw);
|
||||
dws->tx += dws->n_bytes;
|
||||
}
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ static void dw_reader(struct dw_spi *dws)
|
|||
u16 rxw;
|
||||
|
||||
while (max--) {
|
||||
rxw = dw_readl(dws, DW_SPI_DR);
|
||||
rxw = dw_read_io_reg(dws, DW_SPI_DR);
|
||||
/* Care rx only if the transfer's original "rx" is not null */
|
||||
if (dws->rx_end - dws->len) {
|
||||
if (dws->n_bytes == 1)
|
||||
|
|
|
@ -109,6 +109,7 @@ struct dw_spi {
|
|||
u32 fifo_len; /* depth of the FIFO buffer */
|
||||
u32 max_freq; /* max bus freq supported */
|
||||
|
||||
u32 reg_io_width; /* DR I/O width in bytes */
|
||||
u16 bus_num;
|
||||
u16 num_cs; /* supported slave numbers */
|
||||
|
||||
|
@ -145,11 +146,45 @@ static inline u32 dw_readl(struct dw_spi *dws, u32 offset)
|
|||
return __raw_readl(dws->regs + offset);
|
||||
}
|
||||
|
||||
static inline u16 dw_readw(struct dw_spi *dws, u32 offset)
|
||||
{
|
||||
return __raw_readw(dws->regs + offset);
|
||||
}
|
||||
|
||||
static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val)
|
||||
{
|
||||
__raw_writel(val, dws->regs + offset);
|
||||
}
|
||||
|
||||
static inline void dw_writew(struct dw_spi *dws, u32 offset, u16 val)
|
||||
{
|
||||
__raw_writew(val, dws->regs + offset);
|
||||
}
|
||||
|
||||
static inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset)
|
||||
{
|
||||
switch (dws->reg_io_width) {
|
||||
case 2:
|
||||
return dw_readw(dws, offset);
|
||||
case 4:
|
||||
default:
|
||||
return dw_readl(dws, offset);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val)
|
||||
{
|
||||
switch (dws->reg_io_width) {
|
||||
case 2:
|
||||
dw_writew(dws, offset, val);
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
dw_writel(dws, offset, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void spi_enable_chip(struct dw_spi *dws, int enable)
|
||||
{
|
||||
dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sysdev/fsl_soc.h>
|
||||
|
||||
#include "spi-fsl-lib.h"
|
||||
|
@ -85,6 +86,8 @@ struct fsl_espi_transfer {
|
|||
#define SPCOM_TRANLEN(x) ((x) << 0)
|
||||
#define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */
|
||||
|
||||
#define AUTOSUSPEND_TIMEOUT 2000
|
||||
|
||||
static void fsl_espi_change_mode(struct spi_device *spi)
|
||||
{
|
||||
struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
|
||||
|
@ -485,6 +488,8 @@ static int fsl_espi_setup(struct spi_device *spi)
|
|||
mpc8xxx_spi = spi_master_get_devdata(spi->master);
|
||||
reg_base = mpc8xxx_spi->reg_base;
|
||||
|
||||
pm_runtime_get_sync(mpc8xxx_spi->dev);
|
||||
|
||||
hw_mode = cs->hw_mode; /* Save original settings */
|
||||
cs->hw_mode = mpc8xxx_spi_read_reg(
|
||||
®_base->csmode[spi->chip_select]);
|
||||
|
@ -507,6 +512,10 @@ static int fsl_espi_setup(struct spi_device *spi)
|
|||
mpc8xxx_spi_write_reg(®_base->mode, loop_mode);
|
||||
|
||||
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) {
|
||||
cs->hw_mode = hw_mode; /* Restore settings */
|
||||
return retval;
|
||||
|
@ -604,20 +613,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
|
|||
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);
|
||||
}
|
||||
|
||||
static int fsl_espi_suspend(struct spi_master *master)
|
||||
{
|
||||
struct mpc8xxx_spi *mpc8xxx_spi;
|
||||
struct fsl_espi_reg *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;
|
||||
u32 regval;
|
||||
|
||||
mpc8xxx_spi = spi_master_get_devdata(master);
|
||||
reg_base = mpc8xxx_spi->reg_base;
|
||||
|
||||
regval = mpc8xxx_spi_read_reg(®_base->mode);
|
||||
regval &= ~SPMODE_ENABLE;
|
||||
mpc8xxx_spi_write_reg(®_base->mode, regval);
|
||||
|
@ -625,21 +628,20 @@ static int fsl_espi_suspend(struct spi_master *master)
|
|||
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 fsl_espi_reg *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;
|
||||
u32 regval;
|
||||
|
||||
mpc8xxx_spi = spi_master_get_devdata(master);
|
||||
reg_base = mpc8xxx_spi->reg_base;
|
||||
|
||||
regval = mpc8xxx_spi_read_reg(®_base->mode);
|
||||
regval |= SPMODE_ENABLE;
|
||||
mpc8xxx_spi_write_reg(®_base->mode, regval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct spi_master * fsl_espi_probe(struct device *dev,
|
||||
struct resource *mem, unsigned int irq)
|
||||
|
@ -667,25 +669,23 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
|
|||
master->setup = fsl_espi_setup;
|
||||
master->cleanup = fsl_espi_cleanup;
|
||||
master->transfer_one_message = fsl_espi_do_one_msg;
|
||||
master->prepare_transfer_hardware = fsl_espi_resume;
|
||||
master->unprepare_transfer_hardware = fsl_espi_suspend;
|
||||
master->auto_runtime_pm = true;
|
||||
|
||||
mpc8xxx_spi = spi_master_get_devdata(master);
|
||||
mpc8xxx_spi->spi_remove = fsl_espi_remove;
|
||||
|
||||
mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
|
||||
if (!mpc8xxx_spi->reg_base) {
|
||||
ret = -ENOMEM;
|
||||
mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
|
||||
if (IS_ERR(mpc8xxx_spi->reg_base)) {
|
||||
ret = PTR_ERR(mpc8xxx_spi->reg_base);
|
||||
goto err_probe;
|
||||
}
|
||||
|
||||
reg_base = mpc8xxx_spi->reg_base;
|
||||
|
||||
/* 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);
|
||||
if (ret)
|
||||
goto free_irq;
|
||||
goto err_probe;
|
||||
|
||||
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
|
||||
mpc8xxx_spi->rx_shift = 16;
|
||||
|
@ -731,18 +731,27 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
|
|||
|
||||
mpc8xxx_spi_write_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)
|
||||
goto unreg_master;
|
||||
goto err_pm;
|
||||
|
||||
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;
|
||||
|
||||
unreg_master:
|
||||
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
|
||||
free_irq:
|
||||
iounmap(mpc8xxx_spi->reg_base);
|
||||
err_pm:
|
||||
pm_runtime_put_noidle(dev);
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
err_probe:
|
||||
spi_master_put(master);
|
||||
err:
|
||||
|
@ -809,7 +818,9 @@ static int of_fsl_espi_probe(struct platform_device *ofdev)
|
|||
|
||||
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
|
||||
|
@ -824,7 +835,11 @@ static int of_fsl_espi_suspend(struct device *dev)
|
|||
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)
|
||||
|
@ -834,7 +849,7 @@ static int of_fsl_espi_resume(struct device *dev)
|
|||
struct mpc8xxx_spi *mpc8xxx_spi;
|
||||
struct fsl_espi_reg *reg_base;
|
||||
u32 regval;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
mpc8xxx_spi = spi_master_get_devdata(master);
|
||||
reg_base = mpc8xxx_spi->reg_base;
|
||||
|
@ -854,11 +869,17 @@ static int of_fsl_espi_resume(struct device *dev)
|
|||
|
||||
mpc8xxx_spi_write_reg(®_base->mode, regval);
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return spi_master_resume(master);
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
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)
|
||||
};
|
||||
|
||||
|
|
|
@ -114,25 +114,6 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
|
|||
}
|
||||
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)
|
||||
{
|
||||
struct device *dev = &ofdev->dev;
|
||||
|
|
|
@ -54,9 +54,6 @@ struct mpc8xxx_spi {
|
|||
void (*get_rx) (u32 rx_data, 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 irq;
|
||||
|
||||
|
|
|
@ -559,12 +559,6 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
|
|||
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)
|
||||
{
|
||||
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,
|
|||
master->transfer_one_message = fsl_spi_do_one_msg;
|
||||
|
||||
mpc8xxx_spi = spi_master_get_devdata(master);
|
||||
mpc8xxx_spi->spi_remove = fsl_spi_remove;
|
||||
mpc8xxx_spi->max_bits_per_word = 32;
|
||||
mpc8xxx_spi->type = fsl_spi_get_type(dev);
|
||||
|
||||
|
@ -639,10 +632,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
|
|||
if (ret)
|
||||
goto err_cpm_init;
|
||||
|
||||
mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
|
||||
if (mpc8xxx_spi->reg_base == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
|
||||
if (IS_ERR(mpc8xxx_spi->reg_base)) {
|
||||
ret = PTR_ERR(mpc8xxx_spi->reg_base);
|
||||
goto err_probe;
|
||||
}
|
||||
|
||||
if (mpc8xxx_spi->type == TYPE_GRLIB)
|
||||
|
@ -661,11 +654,11 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
|
|||
&mpc8xxx_spi->tx_shift, 8, 1);
|
||||
|
||||
/* Register for SPI Interrupt */
|
||||
ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,
|
||||
0, "fsl_spi", mpc8xxx_spi);
|
||||
ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_spi_irq,
|
||||
0, "fsl_spi", mpc8xxx_spi);
|
||||
|
||||
if (ret != 0)
|
||||
goto free_irq;
|
||||
goto err_probe;
|
||||
|
||||
reg_base = mpc8xxx_spi->reg_base;
|
||||
|
||||
|
@ -686,20 +679,16 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
|
|||
|
||||
mpc8xxx_spi_write_reg(®_base->mode, regval);
|
||||
|
||||
ret = spi_register_master(master);
|
||||
ret = devm_spi_register_master(dev, master);
|
||||
if (ret < 0)
|
||||
goto unreg_master;
|
||||
goto err_probe;
|
||||
|
||||
dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
|
||||
mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
|
||||
|
||||
return master;
|
||||
|
||||
unreg_master:
|
||||
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
|
||||
free_irq:
|
||||
iounmap(mpc8xxx_spi->reg_base);
|
||||
err_ioremap:
|
||||
err_probe:
|
||||
fsl_spi_cpm_free(mpc8xxx_spi);
|
||||
err_cpm_init:
|
||||
spi_master_put(master);
|
||||
|
@ -866,11 +855,8 @@ static int 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);
|
||||
int ret;
|
||||
|
||||
ret = mpc8xxx_spi_remove(&ofdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
fsl_spi_cpm_free(mpc8xxx_spi);
|
||||
if (mpc8xxx_spi->type == TYPE_FSL)
|
||||
of_fsl_spi_free_chipselects(&ofdev->dev);
|
||||
return 0;
|
||||
|
@ -916,7 +902,12 @@ static int plat_mpc8xxx_spi_probe(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");
|
||||
|
|
|
@ -581,6 +581,7 @@ static int img_spfi_probe(struct platform_device *pdev)
|
|||
struct img_spfi *spfi;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
u32 max_speed_hz;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*spfi));
|
||||
if (!master)
|
||||
|
@ -645,6 +646,19 @@ static int img_spfi_probe(struct platform_device *pdev)
|
|||
master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
|
||||
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->cleanup = img_spfi_cleanup;
|
||||
master->transfer_one = img_spfi_transfer_one;
|
||||
|
|
|
@ -30,11 +30,37 @@
|
|||
#include <linux/gpio.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 {
|
||||
void (*cs_control)(struct spi_device *spi, bool on);
|
||||
|
||||
/* driver internal data */
|
||||
struct mpc52xx_psc __iomem *psc;
|
||||
int type;
|
||||
void __iomem *psc;
|
||||
struct mpc512x_psc_fifo __iomem *fifo;
|
||||
unsigned int irq;
|
||||
u8 bits_per_word;
|
||||
|
@ -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 *mps = spi_master_get_devdata(spi->master);
|
||||
struct mpc52xx_psc __iomem *psc = mps->psc;
|
||||
u32 sicr;
|
||||
u32 ccr;
|
||||
int speed;
|
||||
u16 bclkdiv;
|
||||
|
||||
sicr = in_be32(&psc->sicr);
|
||||
sicr = in_be32(psc_addr(mps, sicr));
|
||||
|
||||
/* Set clock phase and polarity */
|
||||
if (spi->mode & SPI_CPHA)
|
||||
|
@ -94,9 +119,9 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
|
|||
sicr |= 0x10000000;
|
||||
else
|
||||
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;
|
||||
speed = cs->speed_hz;
|
||||
if (!speed)
|
||||
|
@ -104,7 +129,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
|
|||
bclkdiv = (mps->mclk_rate / speed) - 1;
|
||||
|
||||
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;
|
||||
|
||||
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,
|
|||
static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *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__);
|
||||
|
||||
/* Zero MR2 */
|
||||
in_8(&psc->mode);
|
||||
out_8(&psc->mode, 0x0);
|
||||
in_8(psc_addr(mps, mr2));
|
||||
out_8(psc_addr(mps, mr2), 0x0);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
|
||||
dev_dbg(&master->dev, "%s()\n", __func__);
|
||||
|
||||
/* 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);
|
||||
|
||||
return 0;
|
||||
|
@ -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,
|
||||
struct mpc512x_psc_spi *mps)
|
||||
{
|
||||
struct mpc52xx_psc __iomem *psc = mps->psc;
|
||||
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
|
||||
u32 sicr;
|
||||
u32 ccr;
|
||||
|
@ -396,12 +418,12 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
|
|||
u16 bclkdiv;
|
||||
|
||||
/* Reset the PSC into a known state */
|
||||
out_8(&psc->command, MPC52xx_PSC_RST_RX);
|
||||
out_8(&psc->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_RST_RX);
|
||||
out_8(psc_addr(mps, command), MPC52xx_PSC_RST_TX);
|
||||
out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
|
||||
|
||||
/* 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 */
|
||||
out_be32(&fifo->tximr, 0);
|
||||
|
@ -417,18 +439,18 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
|
|||
0x00004000 | /* MSTR = 1 -- SPI master */
|
||||
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;
|
||||
speed = 1000000; /* default 1MHz */
|
||||
bclkdiv = (mps->mclk_rate / speed) - 1;
|
||||
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
|
||||
out_be32(&psc->ccr, ccr);
|
||||
out_be32(psc_addr(mps, ccr), ccr);
|
||||
|
||||
/* Set 2ms DTL delay */
|
||||
out_8(&psc->ctur, 0x00);
|
||||
out_8(&psc->ctlr, 0x82);
|
||||
out_8(psc_addr(mps, ctur), 0x00);
|
||||
out_8(psc_addr(mps, ctlr), 0x82);
|
||||
|
||||
/* we don't use the alarms */
|
||||
out_be32(&fifo->rxalarm, 0xfff);
|
||||
|
@ -482,6 +504,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
|||
|
||||
dev_set_drvdata(dev, master);
|
||||
mps = spi_master_get_devdata(master);
|
||||
mps->type = (int)of_device_get_match_data(dev);
|
||||
mps->irq = irq;
|
||||
|
||||
if (pdata == NULL) {
|
||||
|
@ -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[] = {
|
||||
{ .compatible = "fsl,mpc5121-psc-spi", },
|
||||
{ .compatible = "fsl,mpc5121-psc-spi", .data = (void *)TYPE_MPC5121 },
|
||||
{ .compatible = "fsl,mpc5125-psc-spi", .data = (void *)TYPE_MPC5125 },
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue