summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/pcmcia/3c574_cs.c2
-rw-r--r--drivers/net/pcmcia/3c589_cs.c4
-rw-r--r--drivers/serial/serial_cs.c22
-rw-r--r--firmware/Makefile2
-rw-r--r--firmware/WHENCE20
-rw-r--r--firmware/cis/3CCFEM556.cis.ihex13
-rw-r--r--firmware/cis/3CXEM556.cis.ihex13
7 files changed, 68 insertions, 8 deletions
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 8f3872b8985d..f35c609ba020 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -1195,7 +1195,7 @@ static int el3_close(struct net_device *dev)
1195 1195
1196static struct pcmcia_device_id tc574_ids[] = { 1196static struct pcmcia_device_id tc574_ids[] = {
1197 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574), 1197 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
1198 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "3CCFEM556.cis"), 1198 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
1199 PCMCIA_DEVICE_NULL, 1199 PCMCIA_DEVICE_NULL,
1200}; 1200};
1201MODULE_DEVICE_TABLE(pcmcia, tc574_ids); 1201MODULE_DEVICE_TABLE(pcmcia, tc574_ids);
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index cdf661a6092c..ec7cf5ac4f05 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -967,8 +967,8 @@ static struct pcmcia_device_id tc589_ids[] = {
967 PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77), 967 PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
968 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589), 968 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
969 PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202), 969 PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
970 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "3CXEM556.cis"), 970 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"),
971 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "3CXEM556.cis"), 971 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"),
972 PCMCIA_DEVICE_NULL, 972 PCMCIA_DEVICE_NULL,
973}; 973};
974MODULE_DEVICE_TABLE(pcmcia, tc589_ids); 974MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 7546aa887fa7..79c9c5f5cdba 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -681,7 +681,7 @@ static int serial_config(struct pcmcia_device * link)
681 u_char *buf; 681 u_char *buf;
682 cisparse_t *parse; 682 cisparse_t *parse;
683 cistpl_cftable_entry_t *cf; 683 cistpl_cftable_entry_t *cf;
684 int i; 684 int i, last_ret, last_fn;
685 685
686 DEBUG(0, "serial_config(0x%p)\n", link); 686 DEBUG(0, "serial_config(0x%p)\n", link);
687 687
@@ -699,6 +699,16 @@ static int serial_config(struct pcmcia_device * link)
699 tuple->TupleDataMax = 255; 699 tuple->TupleDataMax = 255;
700 tuple->Attributes = 0; 700 tuple->Attributes = 0;
701 701
702 /* Get configuration register information */
703 tuple->DesiredTuple = CISTPL_CONFIG;
704 last_ret = first_tuple(link, tuple, parse);
705 if (last_ret != 0) {
706 last_fn = ParseTuple;
707 goto cs_failed;
708 }
709 link->conf.ConfigBase = parse->config.base;
710 link->conf.Present = parse->config.rmask[0];
711
702 /* Is this a compliant multifunction card? */ 712 /* Is this a compliant multifunction card? */
703 tuple->DesiredTuple = CISTPL_LONGLINK_MFC; 713 tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
704 tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; 714 tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
@@ -761,7 +771,9 @@ static int serial_config(struct pcmcia_device * link)
761 kfree(cfg_mem); 771 kfree(cfg_mem);
762 return 0; 772 return 0;
763 773
764 failed: 774cs_failed:
775 cs_error(link, last_fn, last_ret);
776failed:
765 serial_remove(link); 777 serial_remove(link);
766 kfree(cfg_mem); 778 kfree(cfg_mem);
767 return -ENODEV; 779 return -ENODEV;
@@ -863,10 +875,10 @@ static struct pcmcia_device_id serial_ids[] = {
863 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"), 875 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
864 PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"), 876 PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
865 PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"), 877 PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
866 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "3CCFEM556.cis"), 878 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
867 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"), 879 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"),
868 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"), 880 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"),
869 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"), 881 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"),
870 PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */ 882 PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */
871 PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ 883 PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */
872 PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ 884 PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
diff --git a/firmware/Makefile b/firmware/Makefile
index 1c670e0c0448..96c3dd8cc683 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -48,6 +48,8 @@ fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \
48 e100/d102e_ucode.bin 48 e100/d102e_ucode.bin
49fw-shipped-$(CONFIG_MYRI_SBUS) += myricom/lanai.bin 49fw-shipped-$(CONFIG_MYRI_SBUS) += myricom/lanai.bin
50fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis 50fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis
51fw-shipped-$(CONFIG_PCMCIA_3C589) += cis/3CXEM556.cis
52fw-shipped-$(CONFIG_PCMCIA_3C574) += cis/3CCFEM556.cis
51fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin 53fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin
52fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \ 54fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \
53 advansys/3550.bin advansys/38C0800.bin 55 advansys/3550.bin advansys/38C0800.bin
diff --git a/firmware/WHENCE b/firmware/WHENCE
index c1e9c5ab694c..bb8fda8f06b8 100644
--- a/firmware/WHENCE
+++ b/firmware/WHENCE
@@ -586,6 +586,26 @@ Originally developed by the pcmcia-cs project
586 586
587-------------------------------------------------------------------------- 587--------------------------------------------------------------------------
588 588
589Driver: PCMCIA_3C589 - 3Com PCMCIA adapter
590
591File: cis/3CXEM556.cis
592
593Licence: GPL
594
595Originally developed by the pcmcia-cs project
596
597--------------------------------------------------------------------------
598
599Driver: PCMCIA_3C574 - 3Com PCMCIA adapter
600
601File: cis/3CCFEM556.cis
602
603Licence: GPL
604
605Originally developed by the pcmcia-cs project
606
607--------------------------------------------------------------------------
608
589Driver: PCMCIA_SMC91C92 - SMC 91Cxx PCMCIA 609Driver: PCMCIA_SMC91C92 - SMC 91Cxx PCMCIA
590 610
591File: ositech/Xilinx7OD.bin 611File: ositech/Xilinx7OD.bin
diff --git a/firmware/cis/3CCFEM556.cis.ihex b/firmware/cis/3CCFEM556.cis.ihex
new file mode 100644
index 000000000000..e4d92b173e17
--- /dev/null
+++ b/firmware/cis/3CCFEM556.cis.ihex
@@ -0,0 +1,13 @@
1:1000000001030000FF152D050033436F6D004D65A2
2:100010006761686572747A2033434346454D3535D0
3:1000200036004C414E202B2035366B204D6F6465D9
4:100030006D0000FF20040101560521020000060B9F
5:1000400002004D000000006B000000FF001303439E
6:100050004953210206001A060507001067021B0912
7:1000600087011901556430FFFFFF00130343495313
8:10007000210202001A060527001177021B09A701B9
9:090080001901552330FFFFFF00B8
10:00000001FF
11#
12# This card is MFC-compliant, but identifies itself as single function
13#
diff --git a/firmware/cis/3CXEM556.cis.ihex b/firmware/cis/3CXEM556.cis.ihex
new file mode 100644
index 000000000000..895010b230ff
--- /dev/null
+++ b/firmware/cis/3CXEM556.cis.ihex
@@ -0,0 +1,13 @@
1:1000000001030000FF152C050033436F6D004D65A3
2:100010006761686572747A20334358454D353536CB
3:10002000004C414E202B2035366B204D6F64656DA2
4:100030000000FF20040101350021020000060B0230
5:10004000004C0000000069000000FF00130343495A
6:1000500053210206001A0501070008631B098701E6
7:100060001901556430FFFFFF001303434953210278
8:1000700002001A0501270009631B09A70119015590
9:060080002330FFFFFF002A
10:00000001FF
11#
12# This card is MFC-compliant, but identifies itself as single function
13#
l opt">; /* Tx temp. */ __be16 rpbase; /* Relocation pointer (CPM1 only) */ __be16 res1; /* Reserved */ }; /* SPI Controller mode register definitions */ #define SPMODE_LOOP (1 << 30) #define SPMODE_CI_INACTIVEHIGH (1 << 29) #define SPMODE_CP_BEGIN_EDGECLK (1 << 28) #define SPMODE_DIV16 (1 << 27) #define SPMODE_REV (1 << 26) #define SPMODE_MS (1 << 25) #define SPMODE_ENABLE (1 << 24) #define SPMODE_LEN(x) ((x) << 20) #define SPMODE_PM(x) ((x) << 16) #define SPMODE_OP (1 << 14) #define SPMODE_CG(x) ((x) << 7) /* * Default for SPI Mode: * SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk */ #define SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \ SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf)) /* SPIE register values */ #define SPIE_NE 0x00000200 /* Not empty */ #define SPIE_NF 0x00000100 /* Not full */ /* SPIM register values */ #define SPIM_NE 0x00000200 /* Not empty */ #define SPIM_NF 0x00000100 /* Not full */ #define SPIE_TXB 0x00000200 /* Last char is written to tx fifo */ #define SPIE_RXB 0x00000100 /* Last char is written to rx buf */ /* SPCOM register values */ #define SPCOM_STR (1 << 23) /* Start transmit */ #define SPI_PRAM_SIZE 0x100 #define SPI_MRBLR ((unsigned int)PAGE_SIZE) /* SPI Controller driver's private data. */ struct mpc8xxx_spi { struct device *dev; struct mpc8xxx_spi_reg __iomem *base; /* rx & tx bufs from the spi_transfer */ const void *tx; void *rx; int subblock; struct spi_pram __iomem *pram; struct cpm_buf_desc __iomem *tx_bd; struct cpm_buf_desc __iomem *rx_bd; struct spi_transfer *xfer_in_progress; /* dma addresses for CPM transfers */ dma_addr_t tx_dma; dma_addr_t rx_dma; bool map_tx_dma; bool map_rx_dma; dma_addr_t dma_dummy_tx; dma_addr_t dma_dummy_rx; /* functions to deal with different sized buffers */ void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); u32(*get_tx) (struct mpc8xxx_spi *); unsigned int count; unsigned int irq; unsigned nsecs; /* (clock cycle time)/2 */ u32 spibrg; /* SPIBRG input clock */ u32 rx_shift; /* RX data reg shift when in qe mode */ u32 tx_shift; /* TX data reg shift when in qe mode */ unsigned int flags; struct workqueue_struct *workqueue; struct work_struct work; struct list_head queue; spinlock_t lock; struct completion done; }; static void *mpc8xxx_dummy_rx; static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock); static int mpc8xxx_dummy_rx_refcnt; struct spi_mpc8xxx_cs { /* functions to deal with different sized buffers */ void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); u32 (*get_tx) (struct mpc8xxx_spi *); u32 rx_shift; /* RX data reg shift when in qe mode */ u32 tx_shift; /* TX data reg shift when in qe mode */ u32 hw_mode; /* Holds HW mode register settings */ }; static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val) { out_be32(reg, val); } static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg) { return in_be32(reg); } #define MPC83XX_SPI_RX_BUF(type) \ static \ void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \ { \ type *rx = mpc8xxx_spi->rx; \ *rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \ mpc8xxx_spi->rx = rx; \ } #define MPC83XX_SPI_TX_BUF(type) \ static \ u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \ { \ u32 data; \ const type *tx = mpc8xxx_spi->tx; \ if (!tx) \ return 0; \ data = *tx++ << mpc8xxx_spi->tx_shift; \ mpc8xxx_spi->tx = tx; \ return data; \ } MPC83XX_SPI_RX_BUF(u8) MPC83XX_SPI_RX_BUF(u16) MPC83XX_SPI_RX_BUF(u32) MPC83XX_SPI_TX_BUF(u8) MPC83XX_SPI_TX_BUF(u16) MPC83XX_SPI_TX_BUF(u32) static void mpc8xxx_spi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct spi_mpc8xxx_cs *cs = spi->controller_state; __be32 __iomem *mode = &mspi->base->mode; unsigned long flags; if (cs->hw_mode == mpc8xxx_spi_read_reg(mode)) return; /* Turn off IRQs locally to minimize time that SPI is disabled. */ local_irq_save(flags); /* Turn off SPI unit prior changing mode */ mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE); /* When in CPM mode, we need to reinit tx and rx. */ if (mspi->flags & SPI_CPM_MODE) { if (mspi->flags & SPI_QE) { qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock, QE_CR_PROTOCOL_UNSPECIFIED, 0); } else { cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX); if (mspi->flags & SPI_CPM1) { out_be16(&mspi->pram->rbptr, in_be16(&mspi->pram->rbase)); out_be16(&mspi->pram->tbptr, in_be16(&mspi->pram->tbase)); } } } mpc8xxx_spi_write_reg(mode, cs->hw_mode); local_irq_restore(flags); } static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data; bool pol = spi->mode & SPI_CS_HIGH; struct spi_mpc8xxx_cs *cs = spi->controller_state; if (value == BITBANG_CS_INACTIVE) { if (pdata->cs_control) pdata->cs_control(spi, !pol); } if (value == BITBANG_CS_ACTIVE) { mpc8xxx_spi->rx_shift = cs->rx_shift; mpc8xxx_spi->tx_shift = cs->tx_shift; mpc8xxx_spi->get_rx = cs->get_rx; mpc8xxx_spi->get_tx = cs->get_tx; mpc8xxx_spi_change_mode(spi); if (pdata->cs_control) pdata->cs_control(spi, pol); } } static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs, struct spi_device *spi, struct mpc8xxx_spi *mpc8xxx_spi, int bits_per_word) { cs->rx_shift = 0; cs->tx_shift = 0; if (bits_per_word <= 8) { cs->get_rx = mpc8xxx_spi_rx_buf_u8; cs->get_tx = mpc8xxx_spi_tx_buf_u8; if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { cs->rx_shift = 16; cs->tx_shift = 24; } } else if (bits_per_word <= 16) { cs->get_rx = mpc8xxx_spi_rx_buf_u16; cs->get_tx = mpc8xxx_spi_tx_buf_u16; if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { cs->rx_shift = 16; cs->tx_shift = 16; } } else if (bits_per_word <= 32) { cs->get_rx = mpc8xxx_spi_rx_buf_u32; cs->get_tx = mpc8xxx_spi_tx_buf_u32; } else return -EINVAL; if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE && spi->mode & SPI_LSB_FIRST) { cs->tx_shift = 0; if (bits_per_word <= 8) cs->rx_shift = 8; else cs->rx_shift = 0; } mpc8xxx_spi->rx_shift = cs->rx_shift; mpc8xxx_spi->tx_shift = cs->tx_shift; mpc8xxx_spi->get_rx = cs->get_rx; mpc8xxx_spi->get_tx = cs->get_tx; return bits_per_word; } static int mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs, struct spi_device *spi, int bits_per_word) { /* QE uses Little Endian for words > 8 * so transform all words > 8 into 8 bits * Unfortnatly that doesn't work for LSB so * reject these for now */ /* Note: 32 bits word, LSB works iff * tfcr/rfcr is set to CPMFCR_GBL */ if (spi->mode & SPI_LSB_FIRST && bits_per_word > 8) return -EINVAL; if (bits_per_word > 8) return 8; /* pretend its 8 bits */ return bits_per_word; } static int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi; int bits_per_word; u8 pm; u32 hz; struct spi_mpc8xxx_cs *cs = spi->controller_state; mpc8xxx_spi = spi_master_get_devdata(spi->master); if (t) { bits_per_word = t->bits_per_word; hz = t->speed_hz; } else { bits_per_word = 0; hz = 0; } /* spi_transfer level calls that work per-word */ if (!bits_per_word) bits_per_word = spi->bits_per_word; /* Make sure its a bit width we support [4..16, 32] */ if ((bits_per_word < 4) || ((bits_per_word > 16) && (bits_per_word != 32))) return -EINVAL; if (!hz) hz = spi->max_speed_hz; if (!(mpc8xxx_spi->flags & SPI_CPM_MODE)) bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi, mpc8xxx_spi, bits_per_word); else if (mpc8xxx_spi->flags & SPI_QE) bits_per_word = mspi_apply_qe_mode_quirks(cs, spi, bits_per_word); if (bits_per_word < 0) return bits_per_word; if (bits_per_word == 32) bits_per_word = 0; else bits_per_word = bits_per_word - 1; /* mask out bits we are going to set */ cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16 | SPMODE_PM(0xF)); cs->hw_mode |= SPMODE_LEN(bits_per_word); if ((mpc8xxx_spi->spibrg / hz) > 64) { cs->hw_mode |= SPMODE_DIV16; pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1; WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. " "Will use %d Hz instead.\n", dev_name(&spi->dev), hz, mpc8xxx_spi->spibrg / 1024); if (pm > 16) pm = 16; } else pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1; if (pm) pm--; cs->hw_mode |= SPMODE_PM(pm); mpc8xxx_spi_change_mode(spi); return 0; } static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) { struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd; struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd; unsigned int xfer_len = min(mspi->count, SPI_MRBLR); unsigned int xfer_ofs; xfer_ofs = mspi->xfer_in_progress->len - mspi->count; out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs); out_be16(&rx_bd->cbd_datlen, 0); out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP); out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs); out_be16(&tx_bd->cbd_datlen, xfer_len); out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP | BD_SC_LAST); /* start transfer */ mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR); } static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, bool is_dma_mapped) { struct device *dev = mspi->dev; if (is_dma_mapped) { mspi->map_tx_dma = 0; mspi->map_rx_dma = 0; } else { mspi->map_tx_dma = 1; mspi->map_rx_dma = 1; } if (!t->tx_buf) { mspi->tx_dma = mspi->dma_dummy_tx; mspi->map_tx_dma = 0; } if (!t->rx_buf) { mspi->rx_dma = mspi->dma_dummy_rx; mspi->map_rx_dma = 0; } if (mspi->map_tx_dma) { void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */ mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len, DMA_TO_DEVICE); if (dma_mapping_error(dev, mspi->tx_dma)) { dev_err(dev, "unable to map tx dma\n"); return -ENOMEM; } } else if (t->tx_buf) { mspi->tx_dma = t->tx_dma; } if (mspi->map_rx_dma) { mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len, DMA_FROM_DEVICE); if (dma_mapping_error(dev, mspi->rx_dma)) { dev_err(dev, "unable to map rx dma\n"); goto err_rx_dma; } } else if (t->rx_buf) { mspi->rx_dma = t->rx_dma; } /* enable rx ints */ mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB); mspi->xfer_in_progress = t; mspi->count = t->len; /* start CPM transfers */ mpc8xxx_spi_cpm_bufs_start(mspi); return 0; err_rx_dma: if (mspi->map_tx_dma) dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); return -ENOMEM; } static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) { struct device *dev = mspi->dev;