diff options
| -rw-r--r-- | drivers/spi/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/spi/Makefile | 3 | ||||
| -rw-r--r-- | drivers/spi/dw_spi.c | 33 | ||||
| -rw-r--r-- | drivers/spi/dw_spi_mid.c | 223 | ||||
| -rw-r--r-- | drivers/spi/dw_spi_pci.c | 20 | ||||
| -rw-r--r-- | include/linux/spi/dw_spi.h | 24 |
6 files changed, 283 insertions, 24 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 665d03d4e02..caa2e84cc0a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
| @@ -382,6 +382,10 @@ config SPI_DW_PCI | |||
| 382 | tristate "PCI interface driver for DW SPI core" | 382 | tristate "PCI interface driver for DW SPI core" |
| 383 | depends on SPI_DESIGNWARE && PCI | 383 | depends on SPI_DESIGNWARE && PCI |
| 384 | 384 | ||
| 385 | config SPI_DW_MID_DMA | ||
| 386 | bool "DMA support for DW SPI controller on Intel Moorestown platform" | ||
| 387 | depends on SPI_DW_PCI && INTEL_MID_DMAC | ||
| 388 | |||
| 385 | config SPI_DW_MMIO | 389 | config SPI_DW_MMIO |
| 386 | tristate "Memory-mapped io interface driver for DW SPI core" | 390 | tristate "Memory-mapped io interface driver for DW SPI core" |
| 387 | depends on SPI_DESIGNWARE && HAVE_CLK | 391 | depends on SPI_DESIGNWARE && HAVE_CLK |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 02dad4ae412..7ec375b6c0c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
| @@ -17,7 +17,8 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o | |||
| 17 | obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o | 17 | obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o |
| 18 | obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o | 18 | obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o |
| 19 | obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o | 19 | obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o |
| 20 | obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o | 20 | obj-$(CONFIG_SPI_DW_PCI) += dw_spi_midpci.o |
| 21 | dw_spi_midpci-objs := dw_spi_pci.o dw_spi_mid.o | ||
| 21 | obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o | 22 | obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o |
| 22 | obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o | 23 | obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o |
| 23 | obj-$(CONFIG_SPI_GPIO) += spi_gpio.o | 24 | obj-$(CONFIG_SPI_GPIO) += spi_gpio.o |
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index b50bf5ba873..497ecb3ab83 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c | |||
| @@ -288,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws) | |||
| 288 | */ | 288 | */ |
| 289 | static int map_dma_buffers(struct dw_spi *dws) | 289 | static int map_dma_buffers(struct dw_spi *dws) |
| 290 | { | 290 | { |
| 291 | if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited | 291 | if (!dws->cur_msg->is_dma_mapped |
| 292 | || !dws->cur_chip->enable_dma) | 292 | || !dws->dma_inited |
| 293 | || !dws->cur_chip->enable_dma | ||
| 294 | || !dws->dma_ops) | ||
| 293 | return 0; | 295 | return 0; |
| 294 | 296 | ||
| 295 | if (dws->cur_transfer->tx_dma) | 297 | if (dws->cur_transfer->tx_dma) |
| @@ -341,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg) | |||
| 341 | tasklet_schedule(&dws->pump_transfers); | 343 | tasklet_schedule(&dws->pump_transfers); |
| 342 | } | 344 | } |
| 343 | 345 | ||
| 344 | static void transfer_complete(struct dw_spi *dws) | 346 | void dw_spi_xfer_done(struct dw_spi *dws) |
| 345 | { | 347 | { |
| 346 | /* Update total byte transfered return count actual bytes read */ | 348 | /* Update total byte transfered return count actual bytes read */ |
| 347 | dws->cur_msg->actual_length += dws->len; | 349 | dws->cur_msg->actual_length += dws->len; |
| @@ -356,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws) | |||
| 356 | } else | 358 | } else |
| 357 | tasklet_schedule(&dws->pump_transfers); | 359 | tasklet_schedule(&dws->pump_transfers); |
| 358 | } | 360 | } |
| 361 | EXPORT_SYMBOL_GPL(dw_spi_xfer_done); | ||
| 359 | 362 | ||
| 360 | static irqreturn_t interrupt_transfer(struct dw_spi *dws) | 363 | static irqreturn_t interrupt_transfer(struct dw_spi *dws) |
| 361 | { | 364 | { |
| @@ -387,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) | |||
| 387 | if (dws->tx_end > dws->tx) | 390 | if (dws->tx_end > dws->tx) |
| 388 | spi_umask_intr(dws, SPI_INT_TXEI); | 391 | spi_umask_intr(dws, SPI_INT_TXEI); |
| 389 | else | 392 | else |
| 390 | transfer_complete(dws); | 393 | dw_spi_xfer_done(dws); |
| 391 | } | 394 | } |
| 392 | 395 | ||
| 393 | return IRQ_HANDLED; | 396 | return IRQ_HANDLED; |
| @@ -422,11 +425,7 @@ static void poll_transfer(struct dw_spi *dws) | |||
| 422 | */ | 425 | */ |
| 423 | dws->read(dws); | 426 | dws->read(dws); |
| 424 | 427 | ||
| 425 | transfer_complete(dws); | 428 | dw_spi_xfer_done(dws); |
| 426 | } | ||
| 427 | |||
| 428 | static void dma_transfer(struct dw_spi *dws, int cs_change) | ||
| 429 | { | ||
| 430 | } | 429 | } |
| 431 | 430 | ||
| 432 | static void pump_transfers(unsigned long data) | 431 | static void pump_transfers(unsigned long data) |
| @@ -608,7 +607,7 @@ static void pump_transfers(unsigned long data) | |||
| 608 | } | 607 | } |
| 609 | 608 | ||
| 610 | if (dws->dma_mapped) | 609 | if (dws->dma_mapped) |
| 611 | dma_transfer(dws, cs_change); | 610 | dws->dma_ops->dma_transfer(dws, cs_change); |
| 612 | 611 | ||
| 613 | if (chip->poll_mode) | 612 | if (chip->poll_mode) |
| 614 | poll_transfer(dws); | 613 | poll_transfer(dws); |
| @@ -904,11 +903,17 @@ int __devinit dw_spi_add_host(struct dw_spi *dws) | |||
| 904 | master->setup = dw_spi_setup; | 903 | master->setup = dw_spi_setup; |
| 905 | master->transfer = dw_spi_transfer; | 904 | master->transfer = dw_spi_transfer; |
| 906 | 905 | ||
| 907 | dws->dma_inited = 0; | ||
| 908 | |||
| 909 | /* Basic HW init */ | 906 | /* Basic HW init */ |
| 910 | spi_hw_init(dws); | 907 | spi_hw_init(dws); |
| 911 | 908 | ||
| 909 | if (dws->dma_ops && dws->dma_ops->dma_init) { | ||
| 910 | ret = dws->dma_ops->dma_init(dws); | ||
| 911 | if (ret) { | ||
| 912 | dev_warn(&master->dev, "DMA init failed\n"); | ||
| 913 | dws->dma_inited = 0; | ||
| 914 | } | ||
| 915 | } | ||
| 916 | |||
| 912 | /* Initial and start queue */ | 917 | /* Initial and start queue */ |
| 913 | ret = init_queue(dws); | 918 | ret = init_queue(dws); |
| 914 | if (ret) { | 919 | if (ret) { |
| @@ -933,6 +938,8 @@ int __devinit dw_spi_add_host(struct dw_spi *dws) | |||
| 933 | 938 | ||
| 934 | err_queue_alloc: | 939 | err_queue_alloc: |
| 935 | destroy_queue(dws); | 940 | destroy_queue(dws); |
| 941 | if (dws->dma_ops && dws->dma_ops->dma_exit) | ||
| 942 | dws->dma_ops->dma_exit(dws); | ||
| 936 | err_diable_hw: | 943 | err_diable_hw: |
| 937 | spi_enable_chip(dws, 0); | 944 | spi_enable_chip(dws, 0); |
| 938 | free_irq(dws->irq, dws); | 945 | free_irq(dws->irq, dws); |
| @@ -957,6 +964,8 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws) | |||
| 957 | dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not " | 964 | dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not " |
| 958 | "complete, message memory not freed\n"); | 965 | "complete, message memory not freed\n"); |
| 959 | 966 | ||
| 967 | if (dws->dma_ops && dws->dma_ops->dma_exit) | ||
| 968 | dws->dma_ops->dma_exit(dws); | ||
| 960 | spi_enable_chip(dws, 0); | 969 | spi_enable_chip(dws, 0); |
| 961 | /* Disable clk */ | 970 | /* Disable clk */ |
| 962 | spi_set_clk(dws, 0); | 971 | spi_set_clk(dws, 0); |
diff --git a/drivers/spi/dw_spi_mid.c b/drivers/spi/dw_spi_mid.c new file mode 100644 index 00000000000..c91c966e071 --- /dev/null +++ b/drivers/spi/dw_spi_mid.c | |||
| @@ -0,0 +1,223 @@ | |||
| 1 | /* | ||
| 2 | * dw_spi_mid.c - special handling for DW core on Intel MID platform | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009, Intel Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License along | ||
| 16 | * with this program; if not, write to the Free Software Foundation, | ||
| 17 | * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/dma-mapping.h> | ||
| 21 | #include <linux/dmaengine.h> | ||
| 22 | #include <linux/interrupt.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/spi/spi.h> | ||
| 25 | #include <linux/spi/dw_spi.h> | ||
| 26 | |||
| 27 | #ifdef CONFIG_SPI_DW_MID_DMA | ||
| 28 | #include <linux/intel_mid_dma.h> | ||
| 29 | #include <linux/pci.h> | ||
| 30 | |||
| 31 | struct mid_dma { | ||
| 32 | struct intel_mid_dma_slave dmas_tx; | ||
| 33 | struct intel_mid_dma_slave dmas_rx; | ||
| 34 | }; | ||
| 35 | |||
| 36 | static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param) | ||
| 37 | { | ||
| 38 | struct dw_spi *dws = param; | ||
| 39 | |||
| 40 | return dws->dmac && (&dws->dmac->dev == chan->device->dev); | ||
| 41 | } | ||
| 42 | |||
| 43 | static int mid_spi_dma_init(struct dw_spi *dws) | ||
| 44 | { | ||
| 45 | struct mid_dma *dw_dma = dws->dma_priv; | ||
| 46 | struct intel_mid_dma_slave *rxs, *txs; | ||
| 47 | dma_cap_mask_t mask; | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Get pci device for DMA controller, currently it could only | ||
| 51 | * be the DMA controller of either Moorestown or Medfield | ||
| 52 | */ | ||
| 53 | dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL); | ||
| 54 | if (!dws->dmac) | ||
| 55 | dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL); | ||
| 56 | |||
| 57 | dma_cap_zero(mask); | ||
| 58 | dma_cap_set(DMA_SLAVE, mask); | ||
| 59 | |||
| 60 | /* 1. Init rx channel */ | ||
| 61 | dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws); | ||
| 62 | if (!dws->rxchan) | ||
| 63 | goto err_exit; | ||
| 64 | rxs = &dw_dma->dmas_rx; | ||
| 65 | rxs->hs_mode = LNW_DMA_HW_HS; | ||
| 66 | rxs->cfg_mode = LNW_DMA_PER_TO_MEM; | ||
| 67 | dws->rxchan->private = rxs; | ||
| 68 | |||
| 69 | /* 2. Init tx channel */ | ||
| 70 | dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws); | ||
| 71 | if (!dws->txchan) | ||
| 72 | goto free_rxchan; | ||
| 73 | txs = &dw_dma->dmas_tx; | ||
| 74 | txs->hs_mode = LNW_DMA_HW_HS; | ||
| 75 | txs->cfg_mode = LNW_DMA_MEM_TO_PER; | ||
| 76 | dws->txchan->private = txs; | ||
| 77 | |||
| 78 | dws->dma_inited = 1; | ||
| 79 | return 0; | ||
| 80 | |||
| 81 | free_rxchan: | ||
| 82 | dma_release_channel(dws->rxchan); | ||
| 83 | err_exit: | ||
| 84 | return -1; | ||
| 85 | |||
| 86 | } | ||
| 87 | |||
| 88 | static void mid_spi_dma_exit(struct dw_spi *dws) | ||
| 89 | { | ||
| 90 | dma_release_channel(dws->txchan); | ||
| 91 | dma_release_channel(dws->rxchan); | ||
| 92 | } | ||
| 93 | |||
| 94 | /* | ||
| 95 | * dws->dma_chan_done is cleared before the dma transfer starts, | ||
| 96 | * callback for rx/tx channel will each increment it by 1. | ||
| 97 | * Reaching 2 means the whole spi transaction is done. | ||
| 98 | */ | ||
| 99 | static void dw_spi_dma_done(void *arg) | ||
| 100 | { | ||
| 101 | struct dw_spi *dws = arg; | ||
| 102 | |||
| 103 | if (++dws->dma_chan_done != 2) | ||
| 104 | return; | ||
| 105 | dw_spi_xfer_done(dws); | ||
| 106 | } | ||
| 107 | |||
| 108 | static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) | ||
| 109 | { | ||
| 110 | struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL; | ||
| 111 | struct dma_chan *txchan, *rxchan; | ||
| 112 | struct dma_slave_config txconf, rxconf; | ||
| 113 | u16 dma_ctrl = 0; | ||
| 114 | |||
| 115 | /* 1. setup DMA related registers */ | ||
| 116 | if (cs_change) { | ||
| 117 | spi_enable_chip(dws, 0); | ||
| 118 | dw_writew(dws, dmardlr, 0xf); | ||
| 119 | dw_writew(dws, dmatdlr, 0x10); | ||
| 120 | if (dws->tx_dma) | ||
| 121 | dma_ctrl |= 0x2; | ||
| 122 | if (dws->rx_dma) | ||
| 123 | dma_ctrl |= 0x1; | ||
| 124 | dw_writew(dws, dmacr, dma_ctrl); | ||
| 125 | spi_enable_chip(dws, 1); | ||
| 126 | } | ||
| 127 | |||
| 128 | dws->dma_chan_done = 0; | ||
| 129 | txchan = dws->txchan; | ||
| 130 | rxchan = dws->rxchan; | ||
| 131 | |||
| 132 | /* 2. Prepare the TX dma transfer */ | ||
| 133 | txconf.direction = DMA_TO_DEVICE; | ||
| 134 | txconf.dst_addr = dws->dma_addr; | ||
| 135 | txconf.dst_maxburst = LNW_DMA_MSIZE_16; | ||
| 136 | txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
| 137 | txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
| 138 | |||
| 139 | txchan->device->device_control(txchan, DMA_SLAVE_CONFIG, | ||
| 140 | (unsigned long) &txconf); | ||
| 141 | |||
| 142 | memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl)); | ||
| 143 | dws->tx_sgl.dma_address = dws->tx_dma; | ||
| 144 | dws->tx_sgl.length = dws->len; | ||
| 145 | |||
| 146 | txdesc = txchan->device->device_prep_slave_sg(txchan, | ||
| 147 | &dws->tx_sgl, | ||
| 148 | 1, | ||
| 149 | DMA_TO_DEVICE, | ||
| 150 | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP); | ||
| 151 | txdesc->callback = dw_spi_dma_done; | ||
| 152 | txdesc->callback_param = dws; | ||
| 153 | |||
| 154 | /* 3. Prepare the RX dma transfer */ | ||
| 155 | rxconf.direction = DMA_FROM_DEVICE; | ||
| 156 | rxconf.src_addr = dws->dma_addr; | ||
| 157 | rxconf.src_maxburst = LNW_DMA_MSIZE_16; | ||
| 158 | rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
| 159 | rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
| 160 | |||
| 161 | rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG, | ||
| 162 | (unsigned long) &rxconf); | ||
| 163 | |||
| 164 | memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl)); | ||
| 165 | dws->rx_sgl.dma_address = dws->rx_dma; | ||
| 166 | dws->rx_sgl.length = dws->len; | ||
| 167 | |||
| 168 | rxdesc = rxchan->device->device_prep_slave_sg(rxchan, | ||
| 169 | &dws->rx_sgl, | ||
| 170 | 1, | ||
| 171 | DMA_FROM_DEVICE, | ||
| 172 | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP); | ||
| 173 | rxdesc->callback = dw_spi_dma_done; | ||
| 174 | rxdesc->callback_param = dws; | ||
| 175 | |||
| 176 | /* rx must be started before tx due to spi instinct */ | ||
| 177 | rxdesc->tx_submit(rxdesc); | ||
| 178 | txdesc->tx_submit(txdesc); | ||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | static struct dw_spi_dma_ops mid_dma_ops = { | ||
| 183 | .dma_init = mid_spi_dma_init, | ||
| 184 | .dma_exit = mid_spi_dma_exit, | ||
| 185 | .dma_transfer = mid_spi_dma_transfer, | ||
| 186 | }; | ||
| 187 | #endif | ||
| 188 | |||
| 189 | /* Some specific info for SPI0 controller on Moorestown */ | ||
| 190 | |||
| 191 | /* HW info for MRST CLk Control Unit, one 32b reg */ | ||
| 192 | #define MRST_SPI_CLK_BASE 100000000 /* 100m */ | ||
| 193 | #define MRST_CLK_SPI0_REG 0xff11d86c | ||
| 194 | #define CLK_SPI_BDIV_OFFSET 0 | ||
| 195 | #define CLK_SPI_BDIV_MASK 0x00000007 | ||
| 196 | #define CLK_SPI_CDIV_OFFSET 9 | ||
| 197 | #define CLK_SPI_CDIV_MASK 0x00000e00 | ||
| 198 | #define CLK_SPI_DISABLE_OFFSET 8 | ||
| 199 | |||
| 200 | int dw_spi_mid_init(struct dw_spi *dws) | ||
| 201 | { | ||
| 202 | u32 *clk_reg, clk_cdiv; | ||
| 203 | |||
| 204 | clk_reg = ioremap_nocache(MRST_CLK_SPI0_REG, 16); | ||
| 205 | if (!clk_reg) | ||
| 206 | return -ENOMEM; | ||
| 207 | |||
| 208 | /* get SPI controller operating freq info */ | ||
| 209 | clk_cdiv = (readl(clk_reg) & CLK_SPI_CDIV_MASK) >> CLK_SPI_CDIV_OFFSET; | ||
| 210 | dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1); | ||
| 211 | iounmap(clk_reg); | ||
| 212 | |||
| 213 | dws->num_cs = 16; | ||
| 214 | dws->fifo_len = 40; /* FIFO has 40 words buffer */ | ||
| 215 | |||
| 216 | #ifdef CONFIG_SPI_DW_MID_DMA | ||
| 217 | dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL); | ||
| 218 | if (!dws->dma_priv) | ||
| 219 | return -ENOMEM; | ||
| 220 | dws->dma_ops = &mid_dma_ops; | ||
| 221 | #endif | ||
| 222 | return 0; | ||
| 223 | } | ||
diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c index 1f52755dc87..49ec3aa1219 100644 --- a/drivers/spi/dw_spi_pci.c +++ b/drivers/spi/dw_spi_pci.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * mrst_spi_pci.c - PCI interface driver for DW SPI Core | 2 | * dw_spi_pci.c - PCI interface driver for DW SPI Core |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2009, Intel Corporation. | 4 | * Copyright (c) 2009, Intel Corporation. |
| 5 | * | 5 | * |
| @@ -26,8 +26,8 @@ | |||
| 26 | #define DRIVER_NAME "dw_spi_pci" | 26 | #define DRIVER_NAME "dw_spi_pci" |
| 27 | 27 | ||
| 28 | struct dw_spi_pci { | 28 | struct dw_spi_pci { |
| 29 | struct pci_dev *pdev; | 29 | struct pci_dev *pdev; |
| 30 | struct dw_spi dws; | 30 | struct dw_spi dws; |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | static int __devinit spi_pci_probe(struct pci_dev *pdev, | 33 | static int __devinit spi_pci_probe(struct pci_dev *pdev, |
| @@ -72,9 +72,17 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev, | |||
| 72 | dws->parent_dev = &pdev->dev; | 72 | dws->parent_dev = &pdev->dev; |
| 73 | dws->bus_num = 0; | 73 | dws->bus_num = 0; |
| 74 | dws->num_cs = 4; | 74 | dws->num_cs = 4; |
| 75 | dws->max_freq = 25000000; /* for Moorestwon */ | ||
| 76 | dws->irq = pdev->irq; | 75 | dws->irq = pdev->irq; |
| 77 | dws->fifo_len = 40; /* FIFO has 40 words buffer */ | 76 | |
| 77 | /* | ||
| 78 | * Specific handling for Intel MID paltforms, like dma setup, | ||
| 79 | * clock rate, FIFO depth. | ||
| 80 | */ | ||
| 81 | if (pdev->device == 0x0800) { | ||
| 82 | ret = dw_spi_mid_init(dws); | ||
| 83 | if (ret) | ||
| 84 | goto err_unmap; | ||
| 85 | } | ||
| 78 | 86 | ||
| 79 | ret = dw_spi_add_host(dws); | 87 | ret = dw_spi_add_host(dws); |
| 80 | if (ret) | 88 | if (ret) |
| @@ -140,7 +148,7 @@ static int spi_resume(struct pci_dev *pdev) | |||
| 140 | #endif | 148 | #endif |
| 141 | 149 | ||
| 142 | static const struct pci_device_id pci_ids[] __devinitdata = { | 150 | static const struct pci_device_id pci_ids[] __devinitdata = { |
| 143 | /* Intel Moorestown platform SPI controller 0 */ | 151 | /* Intel MID platform SPI controller 0 */ |
| 144 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) }, | 152 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) }, |
| 145 | {}, | 153 | {}, |
| 146 | }; | 154 | }; |
diff --git a/include/linux/spi/dw_spi.h b/include/linux/spi/dw_spi.h index c91302f3a25..6cd10f6ad47 100644 --- a/include/linux/spi/dw_spi.h +++ b/include/linux/spi/dw_spi.h | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #ifndef DW_SPI_HEADER_H | 1 | #ifndef DW_SPI_HEADER_H |
| 2 | #define DW_SPI_HEADER_H | 2 | #define DW_SPI_HEADER_H |
| 3 | |||
| 3 | #include <linux/io.h> | 4 | #include <linux/io.h> |
| 4 | 5 | ||
| 5 | /* Bit fields in CTRLR0 */ | 6 | /* Bit fields in CTRLR0 */ |
| @@ -82,6 +83,13 @@ struct dw_spi_reg { | |||
| 82 | though only low 16 bits matters */ | 83 | though only low 16 bits matters */ |
| 83 | } __packed; | 84 | } __packed; |
| 84 | 85 | ||
| 86 | struct dw_spi; | ||
| 87 | struct dw_spi_dma_ops { | ||
| 88 | int (*dma_init)(struct dw_spi *dws); | ||
| 89 | void (*dma_exit)(struct dw_spi *dws); | ||
| 90 | int (*dma_transfer)(struct dw_spi *dws, int cs_change); | ||
| 91 | }; | ||
| 92 | |||
| 85 | struct dw_spi { | 93 | struct dw_spi { |
| 86 | struct spi_master *master; | 94 | struct spi_master *master; |
| 87 | struct spi_device *cur_dev; | 95 | struct spi_device *cur_dev; |
| @@ -136,13 +144,15 @@ struct dw_spi { | |||
| 136 | /* Dma info */ | 144 | /* Dma info */ |
| 137 | int dma_inited; | 145 | int dma_inited; |
| 138 | struct dma_chan *txchan; | 146 | struct dma_chan *txchan; |
| 147 | struct scatterlist tx_sgl; | ||
| 139 | struct dma_chan *rxchan; | 148 | struct dma_chan *rxchan; |
| 140 | int txdma_done; | 149 | struct scatterlist rx_sgl; |
| 141 | int rxdma_done; | 150 | int dma_chan_done; |
| 142 | u64 tx_param; | ||
| 143 | u64 rx_param; | ||
| 144 | struct device *dma_dev; | 151 | struct device *dma_dev; |
| 145 | dma_addr_t dma_addr; | 152 | dma_addr_t dma_addr; /* phy address of the Data register */ |
| 153 | struct dw_spi_dma_ops *dma_ops; | ||
| 154 | void *dma_priv; /* platform relate info */ | ||
| 155 | struct pci_dev *dmac; | ||
| 146 | 156 | ||
| 147 | /* Bus interface info */ | 157 | /* Bus interface info */ |
| 148 | void *priv; | 158 | void *priv; |
| @@ -216,4 +226,8 @@ extern int dw_spi_add_host(struct dw_spi *dws); | |||
| 216 | extern void dw_spi_remove_host(struct dw_spi *dws); | 226 | extern void dw_spi_remove_host(struct dw_spi *dws); |
| 217 | extern int dw_spi_suspend_host(struct dw_spi *dws); | 227 | extern int dw_spi_suspend_host(struct dw_spi *dws); |
| 218 | extern int dw_spi_resume_host(struct dw_spi *dws); | 228 | extern int dw_spi_resume_host(struct dw_spi *dws); |
| 229 | extern void dw_spi_xfer_done(struct dw_spi *dws); | ||
| 230 | |||
| 231 | /* platform related setup */ | ||
| 232 | extern int dw_spi_mid_init(struct dw_spi *dws); /* Intel MID platforms */ | ||
| 219 | #endif /* DW_SPI_HEADER_H */ | 233 | #endif /* DW_SPI_HEADER_H */ |
