Commit b1ad487c authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'spi/topic/sunxi', 'spi/topic/tegra114',...

Merge remote-tracking branches 'spi/topic/sunxi', 'spi/topic/tegra114', 'spi/topic/ti-qspi', 'spi/topic/ti-ssp', 'spi/topic/topcliff-pch', 'spi/topic/txx9', 'spi/topic/xcomm' and 'spi/topic/xfer' into spi-next
Allwinner A10 SPI controller
Required properties:
- compatible: Should be "allwinner,sun4-a10-spi".
- reg: Should contain register location and length.
- interrupts: Should contain interrupt.
- clocks: phandle to the clocks feeding the SPI controller. Two are
needed:
- "ahb": the gated AHB parent clock
- "mod": the parent module clock
- clock-names: Must contain the clock names described just above
Example:
spi1: spi@01c06000 {
compatible = "allwinner,sun4i-a10-spi";
reg = <0x01c06000 0x1000>;
interrupts = <11>;
clocks = <&ahb_gates 21>, <&spi1_clk>;
clock-names = "ahb", "mod";
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
};
Allwinner A31 SPI controller
Required properties:
- compatible: Should be "allwinner,sun6i-a31-spi".
- reg: Should contain register location and length.
- interrupts: Should contain interrupt.
- clocks: phandle to the clocks feeding the SPI controller. Two are
needed:
- "ahb": the gated AHB parent clock
- "mod": the parent module clock
- clock-names: Must contain the clock names described just above
- resets: phandle to the reset controller asserting this device in
reset
Example:
spi1: spi@01c69000 {
compatible = "allwinner,sun6i-a31-spi";
reg = <0x01c69000 0x1000>;
interrupts = <0 66 4>;
clocks = <&ahb1_gates 21>, <&spi1_clk>;
clock-names = "ahb", "mod";
resets = <&ahb1_rst 21>;
};
...@@ -458,6 +458,19 @@ config SPI_SIRF ...@@ -458,6 +458,19 @@ config SPI_SIRF
help help
SPI driver for CSR SiRFprimaII SoCs SPI driver for CSR SiRFprimaII SoCs
config SPI_SUN4I
tristate "Allwinner A10 SoCs SPI controller"
depends on ARCH_SUNXI || COMPILE_TEST
help
SPI driver for Allwinner sun4i, sun5i and sun7i SoCs
config SPI_SUN6I
tristate "Allwinner A31 SPI controller"
depends on ARCH_SUNXI || COMPILE_TEST
depends on RESET_CONTROLLER
help
This enables using the SPI controller on the Allwinner A31 SoCs.
config SPI_MXS config SPI_MXS
tristate "Freescale MXS SPI controller" tristate "Freescale MXS SPI controller"
depends on ARCH_MXS depends on ARCH_MXS
...@@ -490,13 +503,6 @@ config SPI_TEGRA20_SLINK ...@@ -490,13 +503,6 @@ config SPI_TEGRA20_SLINK
help help
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
config SPI_TI_SSP
tristate "TI Sequencer Serial Port - SPI Support"
depends on MFD_TI_SSP
help
This selects an SPI master implementation using a TI sequencer
serial port.
config SPI_TOPCLIFF_PCH config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI" tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI depends on PCI
......
...@@ -71,10 +71,11 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o ...@@ -71,10 +71,11 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
......
This diff is collapsed.
This diff is collapsed.
...@@ -846,8 +846,8 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, ...@@ -846,8 +846,8 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
SPI_COMMAND1); SPI_COMMAND1);
tegra_spi_transfer_delay(xfer->delay_usecs); tegra_spi_transfer_delay(xfer->delay_usecs);
goto exit; goto exit;
} else if (msg->transfers.prev == &xfer->transfer_list) { } else if (list_is_last(&xfer->transfer_list,
/* This is the last transfer in message */ &msg->transfers)) {
if (xfer->cs_change) if (xfer->cs_change)
tspi->cs_control = spi; tspi->cs_control = spi;
else { else {
......
...@@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev) ...@@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (res_mmap == NULL) { if (res_mmap == NULL) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"memory mapped resource not required\n"); "memory mapped resource not required\n");
return -ENODEV;
} }
} }
......
/*
* Sequencer Serial Port (SSP) based SPI master driver
*
* Copyright (C) 2010 Texas Instruments Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/mfd/ti_ssp.h>
#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
struct ti_ssp_spi {
struct spi_master *master;
struct device *dev;
spinlock_t lock;
struct list_head msg_queue;
struct completion complete;
bool shutdown;
struct workqueue_struct *workqueue;
struct work_struct work;
u8 mode, bpw;
int cs_active;
u32 pc_en, pc_dis, pc_wr, pc_rd;
void (*select)(int cs);
};
static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
{
u32 ret;
ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
return ret;
}
static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
{
ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
}
static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
struct spi_transfer *t)
{
int count;
if (hw->bpw <= 8) {
u8 *rx = t->rx_buf;
const u8 *tx = t->tx_buf;
for (count = 0; count < t->len; count += 1) {
if (t->tx_buf)
ti_ssp_spi_tx(hw, *tx++);
if (t->rx_buf)
*rx++ = ti_ssp_spi_rx(hw);
}
} else if (hw->bpw <= 16) {
u16 *rx = t->rx_buf;
const u16 *tx = t->tx_buf;
for (count = 0; count < t->len; count += 2) {
if (t->tx_buf)
ti_ssp_spi_tx(hw, *tx++);
if (t->rx_buf)
*rx++ = ti_ssp_spi_rx(hw);
}
} else {
u32 *rx = t->rx_buf;
const u32 *tx = t->tx_buf;
for (count = 0; count < t->len; count += 4) {
if (t->tx_buf)
ti_ssp_spi_tx(hw, *tx++);
if (t->rx_buf)
*rx++ = ti_ssp_spi_rx(hw);
}
}
msg->actual_length += count; /* bytes transferred */
dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
hw->bpw, count, (count < t->len) ? " (under)" : "");
return (count < t->len) ? -EIO : 0; /* left over data */
}
static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
{
cs_active = !!cs_active;
if (cs_active == hw->cs_active)
return;
ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
hw->cs_active = cs_active;
}
#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
cs_en | clk | SSP_COUNT((bits) * 2 - 1))
#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \
cs_en | clk | SSP_COUNT((bits) * 2 - 1))
static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
{
int error, idx = 0;
u32 seqram[16];
u32 cs_en, cs_dis, clk;
u32 topbits, botbits;
mode &= MODE_BITS;
if (mode == hw->mode && bpw == hw->bpw)
return 0;
cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH;
clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW;
/* Construct instructions */
/* Disable Chip Select */
hw->pc_dis = idx;
seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk;
/* Enable Chip Select */
hw->pc_en = idx;
seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
/* Reads and writes need to be split for bpw > 16 */
topbits = (bpw > 16) ? 16 : bpw;
botbits = bpw - topbits;
/* Write */
hw->pc_wr = idx;
seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
if (botbits)
seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG;
seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
/* Read */
hw->pc_rd = idx;
if (botbits)
seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
error = ti_ssp_load(hw->dev, 0, seqram, idx);
if (error < 0)
return error;
error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
0 : SSP_EARLY_DIN));
if (error < 0)
return error;
hw->bpw = bpw;
hw->mode = mode;
return error;
}
static void ti_ssp_spi_work(struct work_struct *work)
{
struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
spin_lock(&hw->lock);
while (!list_empty(&hw->msg_queue)) {
struct spi_message *m;
struct spi_device *spi;
struct spi_transfer *t = NULL;
int status = 0;
m = container_of(hw->msg_queue.next, struct spi_message,
queue);
list_del_init(&m->queue);
spin_unlock(&hw->lock);
spi = m->spi;
if (hw->select)
hw->select(spi->chip_select);
list_for_each_entry(t, &m->transfers, transfer_list) {
int bpw = spi->bits_per_word;
int xfer_status;
if (t->bits_per_word)
bpw = t->bits_per_word;
if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
break;
ti_ssp_spi_chip_select(hw, 1);
xfer_status = ti_ssp_spi_txrx(hw, m, t);
if (xfer_status < 0)
status = xfer_status;
if (t->delay_usecs)
udelay(t->delay_usecs);
if (t->cs_change)
ti_ssp_spi_chip_select(hw, 0);
}
ti_ssp_spi_chip_select(hw, 0);
m->status = status;
m->complete(m->context);
spin_lock(&hw->lock);
}
if (hw->shutdown)
complete(&hw->complete);
spin_unlock(&hw->lock);
}
static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct ti_ssp_spi *hw;
struct spi_transfer *t;
int error = 0;
m->actual_length = 0;
m->status = -EINPROGRESS;
hw = spi_master_get_devdata(spi->master);
if (list_empty(&m->transfers) || !m->complete)
return -EINVAL;
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->len && !(t->rx_buf || t->tx_buf)) {
dev_err(&spi->dev, "invalid xfer, no buffer\n");
return -EINVAL;
}
if (t->len && t->rx_buf && t->tx_buf) {
dev_err(&spi->dev, "invalid xfer, full duplex\n");
return -EINVAL;
}
}
spin_lock(&hw->lock);
if (hw->shutdown) {
error = -ESHUTDOWN;
goto error_unlock;
}
list_add_tail(&m->queue, &hw->msg_queue);
queue_work(hw->workqueue, &hw->work);
error_unlock:
spin_unlock(&hw->lock);
return error;
}
static int ti_ssp_spi_probe(struct platform_device *pdev)
{
const struct ti_ssp_spi_data *pdata;
struct ti_ssp_spi *hw;
struct spi_master *master;
struct device *dev = &pdev->dev;
int error = 0;
pdata = dev_get_platdata(dev);
if (!pdata) {
dev_err(dev, "platform data not found\n");
return -EINVAL;
}
master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
if (!master) {
dev_err(dev, "cannot allocate SPI master\n");
return -ENOMEM;
}
hw = spi_master_get_devdata(master);
platform_set_drvdata(pdev, hw);
hw->master = master;
hw->dev = dev;
hw->select = pdata->select;
spin_lock_init(&hw->lock);
init_completion(&hw->complete);
INIT_LIST_HEAD(&hw->msg_queue);
INIT_WORK(&hw->work, ti_ssp_spi_work);
hw->workqueue = create_singlethread_workqueue(dev_name(dev));
if (!hw->workqueue) {
error = -ENOMEM;
dev_err(dev, "work queue creation failed\n");
goto error_wq;
}
error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
if (error < 0) {
dev_err(dev, "io setup failed\n");
goto error_iosel;
}
master->bus_num = pdev->id;
master->num_chipselect = pdata->num_cs;
master->mode_bits = MODE_BITS;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->flags = SPI_MASTER_HALF_DUPLEX;
master->transfer = ti_ssp_spi_transfer;
error = spi_register_master(master);
if (error) {
dev_err(dev, "master registration failed\n");
goto error_reg;
}
return 0;
error_reg:
error_iosel:
destroy_workqueue(hw->workqueue);
error_wq:
spi_master_put(master);
return error;
}
static int ti_ssp_spi_remove(struct platform_device *pdev)
{
struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
int error;
hw->shutdown = 1;
while (!list_empty(&hw->msg_queue)) {
error = wait_for_completion_interruptible(&hw->complete);
if (error < 0) {
hw->shutdown = 0;
return error;
}
}
destroy_workqueue(hw->workqueue);
spi_unregister_master(hw->master);
return 0;
}
static struct platform_driver ti_ssp_spi_driver = {
.probe = ti_ssp_spi_probe,
.remove = ti_ssp_spi_remove,
.driver = {
.name = "ti-ssp-spi",
.owner = THIS_MODULE,
},
};
module_platform_driver(ti_ssp_spi_driver);
MODULE_DESCRIPTION("SSP SPI Master");
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ti-ssp-spi");
...@@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, ...@@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
data->transfer_active = false; data->transfer_active = false;
wake_up(&data->wait); wake_up(&data->wait);
} else { } else {
dev_err(&data->master->dev, dev_vdbg(&data->master->dev,
"%s : Transfer is not completed", "%s : Transfer is not completed",
__func__); __func__);
} }
...@@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master) ...@@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master)
pch_spi_writereg(master, PCH_SRST, 0x0); pch_spi_writereg(master, PCH_SRST, 0x0);
} }
static int pch_spi_setup(struct spi_device *pspi)
{
/* Check baud rate setting */
/* if baud rate of chip is greater than
max we can support,return error */
if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE)
pspi->max_speed_hz = PCH_MAX_BAUDRATE;
dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__,
(pspi->mode) & (SPI_CPOL | SPI_CPHA));
return 0;
}
static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
{ {
...@@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) ...@@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
int retval; int retval;
unsigned long flags; unsigned long flags;
/* validate spi message and baud rate */
if (unlikely(list_empty(&pmsg->transfers) == 1)) {
dev_err(&pspi->dev, "%s list empty\n", __func__);
retval = -EINVAL;
goto err_out;
}
if (unlikely(pspi->max_speed_hz == 0)) {
dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n",
__func__, pspi->max_speed_hz);
retval = -EINVAL;
goto err_out;
}
dev_dbg(&pspi->dev,
"%s Transfer List not empty. Transfer Speed is set.\n", __func__);
spin_lock_irqsave(&data->lock, flags); spin_lock_irqsave(&data->lock, flags);
/* validate Tx/Rx buffers and Transfer length */ /* validate Tx/Rx buffers and Transfer length */
list_for_each_entry(transfer, &pmsg->transfers, transfer_list) { list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
...@@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) ...@@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
dev_dbg(&pspi->dev, dev_dbg(&pspi->dev,
"%s Tx/Rx buffer valid. Transfer length valid\n", "%s Tx/Rx buffer valid. Transfer length valid\n",
__func__); __func__);
/* if baud rate has been specified validate the same */
if (transfer->speed_hz > PCH_MAX_BAUDRATE)
transfer->speed_hz = PCH_MAX_BAUDRATE;
} }
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
...@@ -1151,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) ...@@ -1151,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
dma->nent = num; dma->nent = num;
dma->desc_tx = desc_tx; dma->desc_tx = desc_tx;
dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing " dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__);
"0x2 to SSNXCR\n", __func__);
spin_lock_irqsave(&data->lock, flags); spin_lock_irqsave(&data->lock, flags);
pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
...@@ -1418,10 +1382,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev) ...@@ -1418,10 +1382,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
/* initialize members of SPI master */ /* initialize members of SPI master */
master->num_chipselect = PCH_MAX_CS; master->num_chipselect = PCH_MAX_CS;
master->setup = pch_spi_setup;
master->transfer = pch_spi_transfer; master->transfer = pch_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->max_speed_hz = PCH_MAX_BAUDRATE;
data->board_dat = board_dat; data->board_dat = board_dat;
data->plat_dev = plat_dev; data->plat_dev = plat_dev;
...@@ -1605,8 +1569,7 @@ static struct platform_driver pch_spi_pd_driver = { ...@@ -1605,8 +1569,7 @@ static struct platform_driver pch_spi_pd_driver = {
.resume = pch_spi_pd_resume .resume = pch_spi_pd_resume
}; };
static int pch_spi_probe(struct pci_dev *pdev, static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
const struct pci_device_id *id)
{ {
struct pch_spi_board_data *board_dat; struct pch_spi_board_data *board_dat;
struct platform_device *pd_dev = NULL; struct platform_device *pd_dev = NULL;
...@@ -1676,6 +1639,8 @@ static int pch_spi_probe(struct pci_dev *pdev, ...@@ -1676,6 +1639,8 @@ static int pch_spi_probe(struct pci_dev *pdev,
return 0; return 0;
err_platform_device: err_platform_device:
while (--i >= 0)
platform_device_unregister(pd_dev_save->pd_save[i]);
pci_disable_device(pdev); pci_disable_device(pdev);
pci_enable_device: pci_enable_device:
pci_release_regions(pdev); pci_release_regions(pdev);
......
...@@ -80,7 +80,6 @@ struct txx9spi { ...@@ -80,7 +80,6 @@ struct txx9spi {
void __iomem *membase; void __iomem *membase;
int baseclk; int baseclk;
struct clk *clk; struct clk *clk;
u32 max_speed_hz, min_speed_hz;
int last_chipselect; int last_chipselect;
int last_chipselect_val; int last_chipselect_val;
}; };
...@@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi) ...@@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi)
{ {
struct txx9spi *c = spi_master_get_devdata(spi->master); struct txx9spi *c = spi_master_get_devdata(spi->master);
if (!spi->max_speed_hz if (!spi->max_speed_hz)
|| spi->max_speed_hz > c->max_speed_hz
|| spi->max_speed_hz < c->min_speed_hz)
return -EINVAL; return -EINVAL;
if (gpio_direction_output(spi->chip_select, if (gpio_direction_output(spi->chip_select,
...@@ -309,15 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) ...@@ -309,15 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
/* check each transfer's parameters */ /* check each transfer's parameters */
list_for_each_entry(t, &m->transfers, transfer_list) { list_for_each_entry(t, &m->transfers, transfer_list) {
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
u8 bits_per_word = t->bits_per_word;
if (!t->tx_buf && !t->rx_buf && t->len) if (!t->tx_buf && !t->rx_buf && t->len)
return -EINVAL; return -EINVAL;
if (t->len & ((bits_per_word >> 3) - 1))
return -EINVAL;
if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
return -EINVAL;
} }
spin_lock_irqsave(&c->lock, flags); spin_lock_irqsave(&c->lock, flags);
...@@ -360,17 +350,12 @@ static int txx9spi_probe(struct platform_device *dev) ...@@ -360,17 +350,12 @@ static int txx9spi_probe(struct platform_device *dev)
goto exit; goto exit;
} }
c->baseclk = clk_get_rate(c->clk); c->baseclk = clk_get_rate(c->clk);
c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1); master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
res = platform_get_resource(dev, IORESOURCE_MEM, 0); res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res) c->membase = devm_ioremap_resource(&dev->dev, res);
goto exit_busy; if (IS_ERR(c->membase))
if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
"spi_txx9"))
goto exit_busy;
c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res));
if (!c->membase)
goto exit_busy; goto exit_busy;
/* enter config mode */ /* enter config mode */
......
...@@ -73,15 +73,13 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm, ...@@ -73,15 +73,13 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
struct spi_device *spi, struct spi_transfer *t, unsigned int *settings) struct spi_device *spi, struct spi_transfer *t, unsigned int *settings)
{ {
unsigned int speed;
if (t->len > 62) if (t->len > 62)
return -EINVAL; return -EINVAL;
speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz; if (t->speed_hz != spi_xcomm->current_speed) {
unsigned int divider;
if (speed != spi_xcomm->current_speed) { divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz);
unsigned int divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, speed);
if (divider >= 64) if (divider >= 64)
*settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64; *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64;
else if (divider >= 16) else if (divider >= 16)
...@@ -89,7 +87,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, ...@@ -89,7 +87,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
else else
*settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4; *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4;
spi_xcomm->current_speed = speed; spi_xcomm->current_speed = t->speed_hz;
} }
if (spi->mode & SPI_CPOL) if (spi->mode & SPI_CPOL)
...@@ -147,8 +145,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master, ...@@ -147,8 +145,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
int status = 0; int status = 0;
bool is_last; bool is_last;
is_first = true;
spi_xcomm_chipselect(spi_xcomm, spi, true); spi_xcomm_chipselect(spi_xcomm, spi, true);
list_for_each_entry(t, &msg->transfers, transfer_list) { list_for_each_entry(t, &msg->transfers, transfer_list) {
......
...@@ -756,6 +756,7 @@ static int spi_transfer_one_message(struct spi_master *master, ...@@ -756,6 +756,7 @@ static int spi_transfer_one_message(struct spi_master *master,
struct spi_transfer *xfer; struct spi_transfer *xfer;
bool keep_cs = false; bool keep_cs = false;
int ret = 0; int ret = 0;
int ms = 1;
spi_set_cs(msg->spi, true); spi_set_cs(msg->spi, true);
...@@ -773,7 +774,16 @@ static int spi_transfer_one_message(struct spi_master *master, ...@@ -773,7 +774,16 @@ static int spi_transfer_one_message(struct spi_master *master,
if (ret > 0) { if (ret > 0) {
ret = 0; ret = 0;
wait_for_completion(&master->xfer_completion); ms = xfer->len * 8 * 1000 / xfer->speed_hz;
ms += 10; /* some tolerance */
ms = wait_for_completion_timeout(&master->xfer_completion,
msecs_to_jiffies(ms));
}
if (ms == 0) {
dev_err(&msg->spi->dev, "SPI transfer timed out\n");
msg->status = -ETIMEDOUT;
} }
trace_spi_transfer_stop(msg, xfer); trace_spi_transfer_stop(msg, xfer);
......
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