diff options
Diffstat (limited to 'drivers')
30 files changed, 646 insertions, 433 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ed9b407e42d..4688dbf2d11 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -536,6 +536,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */ { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */ { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */ + { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci }, /* MCP79 */ { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */ { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */ { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */ diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index c5779ad4abc..3cc27b51465 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_amd" -#define DRV_VERSION "0.3.9" +#define DRV_VERSION "0.3.10" /** * timing_setup - shared timing computation and load @@ -115,7 +115,8 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse } /* UDMA timing */ - pci_write_config_byte(pdev, offset + 0x10 + (3 - dn), t); + if (at.udma) + pci_write_config_byte(pdev, offset + 0x10 + (3 - dn), t); } /** diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index a4175fbdd17..453d72bf259 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -63,7 +63,7 @@ #include <linux/dmi.h> #define DRV_NAME "pata_via" -#define DRV_VERSION "0.3.2" +#define DRV_VERSION "0.3.3" /* * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx @@ -296,7 +296,7 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo } /* Set UDMA unless device is not UDMA capable */ - if (udma_type) { + if (udma_type && t.udma) { u8 cable80_status; /* Get 80-wire cable detection bit */ diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 8d864e5e97e..fe0105d35ba 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2503,6 +2503,15 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) case chip_7042: hp_flags |= MV_HP_PCIE; + if (pdev->vendor == PCI_VENDOR_ID_TTI && + (pdev->device == 0x2300 || pdev->device == 0x2310)) + { + printk(KERN_WARNING "sata_mv: Highpoint RocketRAID BIOS" + " will CORRUPT DATA on attached drives when" + " configured as \"Legacy\". BEWARE!\n"); + printk(KERN_WARNING "sata_mv: Use BIOS \"JBOD\" volumes" + " instead for safety.\n"); + } case chip_6042: hpriv->ops = &mv6xxx_ops; hp_flags |= MV_HP_GEN_IIE; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 44f9e5d9e36..ed5dc7cb50c 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -791,11 +791,13 @@ static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc) static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { - /* Since commands where a result TF is requested are not - executed in ADMA mode, the only time this function will be called - in ADMA mode will be if a command fails. In this case we - don't care about going into register mode with ADMA commands - pending, as the commands will all shortly be aborted anyway. */ + /* Other than when internal or pass-through commands are executed, + the only time this function will be called in ADMA mode will be + if a command fails. In the failure case we don't care about going + into register mode with ADMA commands pending, as the commands will + all shortly be aborted anyway. We assume that NCQ commands are not + issued via passthrough, which is the only way that switching into + ADMA mode could abort outstanding commands. */ nv_adma_register_mode(ap); ata_tf_read(ap, tf); @@ -1359,11 +1361,9 @@ static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc) struct nv_adma_port_priv *pp = qc->ap->private_data; /* ADMA engine can only be used for non-ATAPI DMA commands, - or interrupt-driven no-data commands, where a result taskfile - is not required. */ + or interrupt-driven no-data commands. */ if ((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) || - (qc->tf.flags & ATA_TFLAG_POLLING) || - (qc->flags & ATA_QCFLAG_RESULT_TF)) + (qc->tf.flags & ATA_TFLAG_POLLING)) return 1; if ((qc->flags & ATA_QCFLAG_DMAMAP) || @@ -1381,6 +1381,8 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc) NV_CPB_CTL_IEN; if (nv_adma_use_reg_mode(qc)) { + BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) && + (qc->flags & ATA_QCFLAG_DMAMAP)); nv_adma_register_mode(qc->ap); ata_qc_prep(qc); return; @@ -1425,9 +1427,21 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) VPRINTK("ENTER\n"); + /* We can't handle result taskfile with NCQ commands, since + retrieving the taskfile switches us out of ADMA mode and would abort + existing commands. */ + if (unlikely(qc->tf.protocol == ATA_PROT_NCQ && + (qc->flags & ATA_QCFLAG_RESULT_TF))) { + ata_dev_printk(qc->dev, KERN_ERR, + "NCQ w/ RESULT_TF not allowed\n"); + return AC_ERR_SYSTEM; + } + if (nv_adma_use_reg_mode(qc)) { /* use ATA register mode */ VPRINTK("using ATA register mode: 0x%lx\n", qc->flags); + BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) && + (qc->flags & ATA_QCFLAG_DMAMAP)); nv_adma_register_mode(qc->ap); return ata_qc_issue_prot(qc); } else diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c index fe6d2407bae..c2d23cae951 100644 --- a/drivers/char/cs5535_gpio.c +++ b/drivers/char/cs5535_gpio.c @@ -104,6 +104,11 @@ static ssize_t cs5535_gpio_write(struct file *file, const char __user *data, for (j = 0; j < ARRAY_SIZE(rm); j++) { if (c == rm[j].on) { outl(m1, base + rm[j].wr_offset); + /* If enabling output, turn off AUX 1 and AUX 2 */ + if (c == 'O') { + outl(m0, base + 0x10); + outl(m0, base + 0x14); + } break; } else if (c == rm[j].off) { outl(m0, base + rm[j].wr_offset); diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index f59aecf5ec1..fd9c5d51870 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -267,13 +267,12 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) ts->irq_disabled = 0; enable_irq(spi->irq); - if (req->msg.status) - status = req->msg.status; - - /* on-wire is a must-ignore bit, a BE12 value, then padding */ - sample = be16_to_cpu(req->sample); - sample = sample >> 3; - sample &= 0x0fff; + if (status == 0) { + /* on-wire is a must-ignore bit, a BE12 value, then padding */ + sample = be16_to_cpu(req->sample); + sample = sample >> 3; + sample &= 0x0fff; + } kfree(req); return status ? status : sample; diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index a6469218f19..365024b83d3 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -176,8 +176,6 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) DMA_FROM_DEVICE); status = spi_sync(host->spi, &host->readback); - if (status == 0) - status = host->readback.status; if (host->dma_dev) dma_sync_single_for_cpu(host->dma_dev, @@ -480,8 +478,6 @@ mmc_spi_command_send(struct mmc_spi_host *host, DMA_BIDIRECTIONAL); } status = spi_sync(host->spi, &host->m); - if (status == 0) - status = host->m.status; if (host->dma_dev) dma_sync_single_for_cpu(host->dma_dev, @@ -624,8 +620,6 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t) DMA_BIDIRECTIONAL); status = spi_sync(spi, &host->m); - if (status == 0) - status = host->m.status; if (status != 0) { dev_dbg(&spi->dev, "write error (%d)\n", status); @@ -726,8 +720,6 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t) } status = spi_sync(spi, &host->m); - if (status == 0) - status = host->m.status; if (host->dma_dev) { dma_sync_single_for_cpu(host->dma_dev, @@ -905,8 +897,6 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, DMA_BIDIRECTIONAL); tmp = spi_sync(spi, &host->m); - if (tmp == 0) - tmp = host->m.status; if (host->dma_dev) dma_sync_single_for_cpu(host->dma_dev, diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index c5975047c89..c5975047c89 100755..100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c index 2117c4fbb10..2117c4fbb10 100755..100644 --- a/drivers/net/chelsio/pm3393.c +++ b/drivers/net/chelsio/pm3393.c diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index b301c0428ae..b301c0428ae 100755..100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h index cced9dff91c..cced9dff91c 100755..100644 --- a/drivers/net/chelsio/sge.h +++ b/drivers/net/chelsio/sge.h diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index bf5a7caa5b5..79f7eade477 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -422,7 +422,7 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, (struct bcom_bd **)&bd); - dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_FROM_DEVICE); + dma_unmap_single(&dev->dev, bd->skb_pa, rskb->len, DMA_FROM_DEVICE); /* Test for errors in received frame */ if (status & BCOM_FEC_RX_BD_ERRORS) { @@ -467,7 +467,7 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) bcom_prepare_next_buffer(priv->rx_dmatsk); bd->status = FEC_RX_BUFFER_SIZE; - bd->skb_pa = dma_map_single(&dev->dev, rskb->data, + bd->skb_pa = dma_map_single(&dev->dev, skb->data, FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); bcom_submit_next_buffer(priv->rx_dmatsk, skb); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 38268d7335a..0431e9ed0fa 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -696,7 +696,7 @@ int startup_gfar(struct net_device *dev) { struct txbd8 *txbdp; struct rxbd8 *rxbdp; - dma_addr_t addr; + dma_addr_t addr = 0; unsigned long vaddr; int i; struct gfar_private *priv = netdev_priv(dev); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 0f306ddb563..8def8657251 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1979,6 +1979,7 @@ static int myri10ge_open(struct net_device *dev) lro_mgr->lro_arr = mgp->rx_done.lro_desc; lro_mgr->get_frag_header = myri10ge_get_frag_header; lro_mgr->max_aggr = myri10ge_lro_max_pkts; + lro_mgr->frag_align_pad = 2; if (lro_mgr->max_aggr > MAX_SKB_FRAGS) lro_mgr->max_aggr = MAX_SKB_FRAGS; diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 09b4fde8d92..816a59e801b 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -586,7 +586,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) /* CRC error flagged */ mac->netdev->stats.rx_errors++; mac->netdev->stats.rx_crc_errors++; - dev_kfree_skb_irq(skb); + /* No need to free skb, it'll be reused */ goto next; } @@ -1362,7 +1362,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); - dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX | NETIF_F_SG; + dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG; /* These should come out of the device tree eventually */ mac->dma_txch = index; diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index fc2f0e695a1..c30196d0ad1 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -91,9 +91,12 @@ int mdiobus_register(struct mii_bus *bus) err = device_register(&phydev->dev); - if (err) + if (err) { printk(KERN_ERR "phy %d failed to register\n", i); + phy_device_free(phydev); + phydev = NULL; + } } bus->phy_map[i] = phydev; @@ -110,10 +113,8 @@ void mdiobus_unregister(struct mii_bus *bus) int i; for (i = 0; i < PHY_MAX_ADDR; i++) { - if (bus->phy_map[i]) { + if (bus->phy_map[i]) device_unregister(&bus->phy_map[i]->dev); - kfree(bus->phy_map[i]); - } } } EXPORT_SYMBOL(mdiobus_unregister); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index f6e484812a9..5b9e1751e1b 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -44,6 +44,16 @@ static struct phy_driver genphy_driver; extern int mdio_bus_init(void); extern void mdio_bus_exit(void); +void phy_device_free(struct phy_device *phydev) +{ + kfree(phydev); +} + +static void phy_device_release(struct device *dev) +{ + phy_device_free(to_phy_device(dev)); +} + struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) { struct phy_device *dev; @@ -54,6 +64,8 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) if (NULL == dev) return (struct phy_device*) PTR_ERR((void*)-ENOMEM); + dev->dev.release = phy_device_release; + dev->speed = 0; dev->duplex = -1; dev->pause = dev->asym_pause = 0; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3d1dfc94840..6197afb3ed8 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2906,16 +2906,14 @@ static void sky2_restart(struct work_struct *work) int i, err; rtnl_lock(); - sky2_write32(hw, B0_IMSK, 0); - sky2_read32(hw, B0_IMSK); - napi_disable(&hw->napi); - for (i = 0; i < hw->ports; i++) { dev = hw->dev[i]; if (netif_running(dev)) sky2_down(dev); } + napi_disable(&hw->napi); + sky2_write32(hw, B0_IMSK, 0); sky2_reset(hw); sky2_write32(hw, B0_IMSK, Y2_IS_BASE); napi_enable(&hw->napi); diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 1a3d80bfe9e..76cc1d3adf7 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1299,9 +1299,9 @@ smc911x_rx_dma_irq(int dma, void *data) PRINT_PKT(skb->data, skb->len); dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; + netif_rx(skb); spin_lock_irqsave(&lp->lock, flags); pkts = (SMC_GET_RX_FIFO_INF() & RX_FIFO_INF_RXSUSED_) >> 16; diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index a4f56e95cf9..f1e00ff54ce 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -293,7 +293,7 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) return -EINVAL; /* Cannot register while the char dev is in use */ - if (test_and_set_bit(RTC_DEV_BUSY, &rtc->flags)) + if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) return -EBUSY; spin_lock_irq(&rtc->irq_task_lock); @@ -303,7 +303,7 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) } spin_unlock_irq(&rtc->irq_task_lock); - clear_bit(RTC_DEV_BUSY, &rtc->flags); + clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); return retval; } diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index ae1bf177d62..025c60a17a4 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -26,7 +26,7 @@ static int rtc_dev_open(struct inode *inode, struct file *file) struct rtc_device, char_dev); const struct rtc_class_ops *ops = rtc->ops; - if (test_and_set_bit(RTC_DEV_BUSY, &rtc->flags)) + if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) return -EBUSY; file->private_data = rtc; @@ -41,7 +41,7 @@ static int rtc_dev_open(struct inode *inode, struct file *file) } /* something has gone wrong */ - clear_bit(RTC_DEV_BUSY, &rtc->flags); + clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); return err; } @@ -402,7 +402,7 @@ static int rtc_dev_release(struct inode *inode, struct file *file) if (rtc->ops->release) rtc->ops->release(rtc->dev.parent); - clear_bit(RTC_DEV_BUSY, &rtc->flags); + clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); return 0; } diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 3e183cfee10..1f956dc5d56 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -89,13 +89,9 @@ static int max6902_get_reg(struct device *dev, unsigned char address, /* do the i/o */ status = spi_sync(spi, &message); - if (status == 0) - status = message.status; - else - return status; - - *data = chip->rx_buf[1]; + if (status == 0) + *data = chip->rx_buf[1]; return status; } @@ -125,9 +121,7 @@ static int max6902_get_datetime(struct device *dev, struct rtc_time *dt) /* do the i/o */ status = spi_sync(spi, &message); - if (status == 0) - status = message.status; - else + if (status) return status; /* The chip sends data in this order: diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 5e083d1f57e..15a5789b773 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -472,11 +472,11 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char if (rc) goto unregister_dev; - add_disk(dev_info->gd); - blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); + add_disk(dev_info->gd); + switch (dev_info->segment_type) { case SEG_TYPE_SR: case SEG_TYPE_ER: diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 6db31089d2d..c3df2cd009a 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -451,6 +451,7 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data) break; case -ENXIO: case -ENOMEM: + case -EIO: /* These should abort looping */ break; default: diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 2f6bf462425..156f3f9786b 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -113,6 +113,7 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) { struct subchannel *sch; struct ccw1 *ccw; + int ret; sch = to_subchannel(cdev->dev.parent); /* Setup sense channel program. */ @@ -124,9 +125,25 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) /* Reset device status. */ memset(&cdev->private->irb, 0, sizeof(struct irb)); - cdev->private->flags.intretry = 0; - return cio_start(sch, ccw, LPM_ANYPATH); + /* Try on every path. */ + ret = -ENODEV; + while (cdev->private->imask != 0) { + if ((sch->opm & cdev->private->imask) != 0 && + cdev->private->iretry > 0) { + cdev->private->iretry--; + /* Reset internal retry indication. */ + cdev->private->flags.intretry = 0; + ret = cio_start (sch, cdev->private->iccws, + cdev->private->imask); + /* ret is 0, -EBUSY, -EACCES or -ENODEV */ + if (ret != -EACCES) + return ret; + } + cdev->private->imask >>= 1; + cdev->private->iretry = 5; + } + return ret; } void @@ -136,7 +153,8 @@ ccw_device_sense_id_start(struct ccw_device *cdev) memset (&cdev->private->senseid, 0, sizeof (struct senseid)); cdev->private->senseid.cu_type = 0xFFFF; - cdev->private->iretry = 3; + cdev->private->imask = 0x80; + cdev->private->iretry = 5; ret = __ccw_device_sense_id_start(cdev); if (ret && ret != -EBUSY) ccw_device_sense_id_done(cdev, ret); @@ -252,13 +270,14 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_sense_id_done(cdev, ret); break; case -EACCES: /* channel is not operational. */ + sch->lpm &= ~cdev->private->imask; + cdev->private->imask >>= 1; + cdev->private->iretry = 5; + /* fall through. */ case -EAGAIN: /* try again. */ - cdev->private->iretry--; - if (cdev->private->iretry > 0) { - ret = __ccw_device_sense_id_start(cdev); - if (ret == 0 || ret == -EBUSY) - break; - } + ret = __ccw_device_sense_id_start(cdev); + if (ret == 0 || ret == -EBUSY) + break; /* fall through. */ default: /* Sense ID failed. Try asking VM. */ if (MACHINE_IS_VM) { diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index b3b6f654365..97adc701a81 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -2802,7 +2802,6 @@ void ctc_init_netdevice(struct net_device * dev) dev->type = ARPHRD_SLIP; dev->tx_queue_len = 100; dev->flags = IFF_POINTOPOINT | IFF_NOARP; - SET_MODULE_OWNER(dev); } diff --git a/drivers/spi/at25.c b/drivers/spi/at25.c index e007833cca5..290dbe99647 100644 --- a/drivers/spi/at25.c +++ b/drivers/spi/at25.c @@ -21,6 +21,13 @@ #include <linux/spi/eeprom.h> +/* + * NOTE: this is an *EEPROM* driver. The vagaries of product naming + * mean that some AT25 products are EEPROMs, and others are FLASH. + * Handle FLASH chips with the drivers/mtd/devices/m25p80.c driver, + * not this one! + */ + struct at25_data { struct spi_device *spi; struct mutex lock; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b31f4431849..93e9de46977 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -541,10 +541,7 @@ static void spi_complete(void *arg) * Also, the caller is guaranteeing that the memory associated with the * message will not be freed before this call returns. * - * The return value is a negative error code if the message could not be - * submitted, else zero. When the value is zero, then message->status is - * also defined; it's the completion code for the transfer, either zero - * or a negative error code from the controller driver. + * It returns zero on success, else a negative error code. */ int spi_sync(struct spi_device *spi, struct spi_message *message) { @@ -554,8 +551,10 @@ int spi_sync(struct spi_device *spi, struct spi_message *message) message->complete = spi_complete; message->context = &done; status = spi_async(spi, message); - if (status == 0) + if (status == 0) { wait_for_completion(&done); + status = message->status; + } message->context = NULL; return status; } @@ -589,7 +588,7 @@ int spi_write_then_read(struct spi_device *spi, const u8 *txbuf, unsigned n_tx, u8 *rxbuf, unsigned n_rx) { - static DECLARE_MUTEX(lock); + static DEFINE_MUTEX(lock); int status; struct spi_message message; @@ -615,7 +614,7 @@ int spi_write_then_read(struct spi_device *spi, } /* ... unless someone else is using the pre-allocated buffer */ - if (down_trylock(&lock)) { + if (!mutex_trylock(&lock)) { local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); if (!local_buf) return -ENOMEM; @@ -628,13 +627,11 @@ int spi_write_then_read(struct spi_device *spi, /* do the i/o */ status = spi_sync(spi, &message); - if (status == 0) { + if (status == 0) memcpy(rxbuf, x[1].rx_buf, n_rx); - status = message.status; - } if (x[0].tx_buf == buf) - up(&lock); + mutex_unlock(&lock); else kfree(local_buf); diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 2ef11bb70b2..22697b81220 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1,17 +1,22 @@ /* - * File: drivers/spi/bfin5xx_spi.c - * Based on: N/A - * Author: Luke Yang (Analog Devices Inc.) + * File: drivers/spi/bfin5xx_spi.c + * Maintainer: + * Bryan Wu <bryan.wu@analog.com> + * Original Author: + * Luke Yang (Analog Devices Inc.) * - * Created: March. 10th 2006 - * Description: SPI controller driver for Blackfin 5xx - * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * Created: March. 10th 2006 + * Description: SPI controller driver for Blackfin BF5xx + * Bugs: Enter bugs at http://blackfin.uclinux.org/ * * Modified: * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang) * August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang) + * July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu) + * July 30, 2007 add platfrom_resource interface to support multi-port + * SPI controller (Bryan Wu) * - * Copyright 2004-2006 Analog Devices Inc. + * Copyright 2004-2007 Analog Devices 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 @@ -31,50 +36,39 @@ #include <linux/init.h> #include <linux/module.h> +#include <linux/delay.h> #include <linux/device.h> +#include <linux/io.h> #include <linux/ioport.h> +#include <linux/irq.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/spi/spi.h> #include <linux/workqueue.h> -#include <linux/delay.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/delay.h> #include <asm/dma.h> - +#include <asm/portmux.h> #include <asm/bfin5xx_spi.h> -MODULE_AUTHOR("Luke Yang"); -MODULE_DESCRIPTION("Blackfin 5xx SPI Contoller"); -MODULE_LICENSE("GPL"); +#define DRV_NAME "bfin-spi" +#define DRV_AUTHOR "Bryan Wu, Luke Yang" +#define DRV_DESC "Blackfin BF5xx on-chip SPI Contoller Driver" +#define DRV_VERSION "1.0" -#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0) +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESC); +MODULE_LICENSE("GPL"); -#define DEFINE_SPI_REG(reg, off) \ -static inline u16 read_##reg(void) \ - { return *(volatile unsigned short*)(SPI0_REGBASE + off); } \ -static inline void write_##reg(u16 v) \ - {*(volatile unsigned short*)(SPI0_REGBASE + off) = v;\ - SSYNC();} +#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07) == 0) -DEFINE_SPI_REG(CTRL, 0x00) -DEFINE_SPI_REG(FLAG, 0x04) -DEFINE_SPI_REG(STAT, 0x08) -DEFINE_SPI_REG(TDBR, 0x0C) -DEFINE_SPI_REG(RDBR, 0x10) -DEFINE_SPI_REG(BAUD, 0x14) -DEFINE_SPI_REG(SHAW, 0x18) -#define START_STATE ((void*)0) -#define RUNNING_STATE ((void*)1) -#define DONE_STATE ((void*)2) -#define ERROR_STATE ((void*)-1) -#define QUEUE_RUNNING 0 -#define QUEUE_STOPPED 1 -int dma_requested; +#define START_STATE ((void *)0) +#define RUNNING_STATE ((void *)1) +#define DONE_STATE ((void *)2) +#define ERROR_STATE ((void *)-1) +#define QUEUE_RUNNING 0 +#define QUEUE_STOPPED 1 struct driver_data { /* Driver model hookup */ @@ -83,6 +77,12 @@ struct driver_data { /* SPI framework hookup */ struct spi_master *master; + /* Regs base of SPI controller */ + void __iomem *regs_base; + + /* Pin request list */ + u16 *pin_req; + /* BFIN hookup */ struct bfin5xx_spi_master *master_info; @@ -107,12 +107,18 @@ struct driver_data { void *tx_end; void *rx; void *rx_end; + + /* DMA stuffs */ + int dma_channel; int dma_mapped; + int dma_requested; dma_addr_t rx_dma; dma_addr_t tx_dma; + size_t rx_map_len; size_t tx_map_len; u8 n_bytes; + int cs_change; void (*write) (struct driver_data *); void (*read) (struct driver_data *); void (*duplex) (struct driver_data *); @@ -129,28 +135,40 @@ struct chip_data { u8 enable_dma; u8 bits_per_word; /* 8 or 16 */ u8 cs_change_per_word; - u8 cs_chg_udelay; + u16 cs_chg_udelay; /* Some devices require > 255usec delay */ void (*write) (struct driver_data *); void (*read) (struct driver_data *); void (*duplex) (struct driver_data *); }; +#define DEFINE_SPI_REG(reg, off) \ +static inline u16 read_##reg(struct driver_data *drv_data) \ + { return bfin_read16(drv_data->regs_base + off); } \ +static inline void write_##reg(struct driver_data *drv_data, u16 v) \ + { bfin_write16(drv_data->regs_base + off, v); } + +DEFINE_SPI_REG(CTRL, 0x00) +DEFINE_SPI_REG(FLAG, 0x04) +DEFINE_SPI_REG(STAT, 0x08) +DEFINE_SPI_REG(TDBR, 0x0C) +DEFINE_SPI_REG(RDBR, 0x10) +DEFINE_SPI_REG(BAUD, 0x14) +DEFINE_SPI_REG(SHAW, 0x18) + static void bfin_spi_enable(struct driver_data *drv_data) { u16 cr; - cr = read_CTRL(); - write_CTRL(cr | BIT_CTL_ENABLE); - SSYNC(); + cr = read_CTRL(drv_data); + write_CTRL(drv_data, (cr | BIT_CTL_ENABLE)); } static void bfin_spi_disable(struct driver_data *drv_data) { u16 cr; - cr = read_CTRL(); - write_CTRL(cr & (~BIT_CTL_ENABLE)); - SSYNC(); + cr = read_CTRL(drv_data); + write_CTRL(drv_data, (cr & (~BIT_CTL_ENABLE))); } /* Caculate the SPI_BAUD register value based on input HZ */ @@ -170,83 +188,71 @@ static int flush(struct driver_data *drv_data) unsigned long limit = loops_per_jiffy << 1; /* wait for stop and clear stat */ - while (!(read_STAT() & BIT_STAT_SPIF) && limit--) - continue; + while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && limit--) + cpu_relax(); - write_STAT(BIT_STAT_CLR); + write_STAT(drv_data, BIT_STAT_CLR); return limit; } +/* Chip select operation functions for cs_change flag */ +static void cs_active(struct driver_data *drv_data, struct chip_data *chip) +{ + u16 flag = read_FLAG(drv_data); + + flag |= chip->flag; + flag &= ~(chip->flag << 8); + + write_FLAG(drv_data, flag); +} + +static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip) +{ + u16 flag = read_FLAG(drv_data); + + flag |= (chip->flag << 8); + + write_FLAG(drv_data, flag); + + /* Move delay here for consistency */ + if (chip->cs_chg_udelay) + udelay(chip->cs_chg_udelay); +} + +#define MAX_SPI_SSEL 7 + /* stop controller and re-config current chip*/ -static void restore_state(struct driver_data *drv_data) +static int restore_state(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; + int ret = 0; /* Clear status and disable clock */ - write_STAT(BIT_STAT_CLR); + write_STAT(drv_data, BIT_STAT_CLR); bfin_spi_disable(drv_data); dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n"); -#if defined(CONFIG_BF534) || defined(CONFIG_BF536) || defined(CONFIG_BF537) - dev_dbg(&drv_data->pdev->dev, - "chip select number is %d\n", chip->chip_select_num); - - switch (chip->chip_select_num) { - case 1: - bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3c00); - SSYNC(); - break; - - case 2: - case 3: - bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJSE_SPI); - SSYNC(); - bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800); - SSYNC(); - break; - - case 4: - bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS4E_SPI); - SSYNC(); - bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3840); - SSYNC(); - break; + /* Load the registers */ + write_CTRL(drv_data, chip->ctl_reg); + write_BAUD(drv_data, chip->baud); - case 5: - bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS5E_SPI); - SSYNC(); - bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3820); - SSYNC(); - break; + bfin_spi_enable(drv_data); + cs_active(drv_data, chip); - case 6: - bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS6E_SPI); - SSYNC(); - bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3810); - SSYNC(); - break; + if (ret) + dev_dbg(&drv_data->pdev->dev, + ": request chip select number %d failed\n", + chip->chip_select_num); - case 7: - bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJCE_SPI); - SSYNC(); - bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800); - SSYNC(); - break; - } -#endif - - /* Load the registers */ - write_CTRL(chip->ctl_reg); - write_BAUD(chip->baud); - write_FLAG(chip->flag); + return ret; } /* used to kick off transfer in rx mode */ -static unsigned short dummy_read(void) +static unsigned short dummy_read(struct driver_data *drv_data) { unsigned short tmp; - tmp = read_RDBR(); + tmp = read_RDBR(drv_data); return tmp; } @@ -255,9 +261,9 @@ static void null_writer(struct driver_data *drv_data) u8 n_bytes = drv_data->n_bytes; while (drv_data->tx < drv_data->tx_end) { - write_TDBR(0); - while ((read_STAT() & BIT_STAT_TXS)) - continue; + write_TDBR(drv_data, 0); + while ((read_STAT(drv_data) & BIT_STAT_TXS)) + cpu_relax(); drv_data->tx += n_bytes; } } @@ -265,75 +271,78 @@ static void null_writer(struct driver_data *drv_data) static void null_reader(struct driver_data *drv_data) { u8 n_bytes = drv_data->n_bytes; - dummy_read(); + dummy_read(drv_data); while (drv_data->rx < drv_data->rx_end) { - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - dummy_read(); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + dummy_read(drv_data); drv_data->rx += n_bytes; } } static void u8_writer(struct driver_data *drv_data) { - dev_dbg(&drv_data->pdev->dev, - "cr8-s is 0x%x\n", read_STAT()); + dev_dbg(&drv_data->pdev->dev, + "cr8-s is 0x%x\n", read_STAT(drv_data)); + + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + while (drv_data->tx < drv_data->tx_end) { - write_TDBR(*(u8 *) (drv_data->tx)); - while (read_STAT() & BIT_STAT_TXS) - continue; + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + while (read_STAT(drv_data) & BIT_STAT_TXS) + cpu_relax(); ++drv_data->tx; } - - /* poll for SPI completion before returning */ - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; } static void u8_cs_chg_writer(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + while (drv_data->tx < drv_data->tx_end) { - write_FLAG(chip->flag); - SSYNC(); - - write_TDBR(*(u8 *) (drv_data->tx)); - while (read_STAT() & BIT_STAT_TXS) - continue; - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; - write_FLAG(0xFF00 | chip->flag); - SSYNC(); - if (chip->cs_chg_udelay) - udelay(chip->cs_chg_udelay); + cs_active(drv_data, chip); + + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + while (read_STAT(drv_data) & BIT_STAT_TXS) + cpu_relax(); + + cs_deactive(drv_data, chip); + ++drv_data->tx; } - write_FLAG(0xFF00); - SSYNC(); } static void u8_reader(struct driver_data *drv_data) { - dev_dbg(&drv_data->pdev->dev, - "cr-8 is 0x%x\n", read_STAT()); + dev_dbg(&drv_data->pdev->dev, + "cr-8 is 0x%x\n", read_STAT(drv_data)); + + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); /* clear TDBR buffer before read(else it will be shifted out) */ - write_TDBR(0xFFFF); + write_TDBR(drv_data, 0xFFFF); - dummy_read(); + dummy_read(drv_data); while (drv_data->rx < drv_data->rx_end - 1) { - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - *(u8 *) (drv_data->rx) = read_RDBR(); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); ++drv_data->rx; } - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - *(u8 *) (drv_data->rx) = read_SHAW(); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u8 *) (drv_data->rx) = read_SHAW(drv_data); ++drv_data->rx; } @@ -341,36 +350,47 @@ static void u8_cs_chg_reader(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; - while (drv_data->rx < drv_data->rx_end) { - write_FLAG(chip->flag); - SSYNC(); - - read_RDBR(); /* kick off */ - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; - *(u8 *) (drv_data->rx) = read_SHAW(); - write_FLAG(0xFF00 | chip->flag); - SSYNC(); - if (chip->cs_chg_udelay) - udelay(chip->cs_chg_udelay); + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + + /* clear TDBR buffer before read(else it will be shifted out) */ + write_TDBR(drv_data, 0xFFFF); + + cs_active(drv_data, chip); + dummy_read(drv_data); + + while (drv_data->rx < drv_data->rx_end - 1) { + cs_deactive(drv_data, chip); + + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + cs_active(drv_data, chip); + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); ++drv_data->rx; } - write_FLAG(0xFF00); - SSYNC(); + cs_deactive(drv_data, chip); + + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u8 *) (drv_data->rx) = read_SHAW(drv_data); + ++drv_data->rx; } static void u8_duplex(struct driver_data *drv_data) { + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + /* in duplex mode, clk is triggered by writing of TDBR */ while (drv_data->rx < drv_data->rx_end) { - write_TDBR(*(u8 *) (drv_data->tx)); - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - *(u8 *) (drv_data->rx) = read_RDBR(); + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + while (read_STAT(drv_data) & BIT_STAT_TXS) + cpu_relax(); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); ++drv_data->rx; ++drv_data->tx; } @@ -380,83 +400,89 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + while (drv_data->rx < drv_data->rx_end) { - write_FLAG(chip->flag); - SSYNC(); - - write_TDBR(*(u8 *) (drv_data->tx)); - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - *(u8 *) (drv_data->rx) = read_RDBR(); - write_FLAG(0xFF00 | chip->flag); - SSYNC(); - if (chip->cs_chg_udelay) - udelay(chip->cs_chg_udelay); + cs_active(drv_data, chip); + + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + while (read_STAT(drv_data) & BIT_STAT_TXS) + cpu_relax(); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); + + cs_deactive(drv_data, chip); + ++drv_data->rx; ++drv_data->tx; } - write_FLAG(0xFF00); - SSYNC(); } static void u16_writer(struct driver_data *drv_data) { - dev_dbg(&drv_data->pdev->dev, - "cr16 is 0x%x\n", read_STAT()); + dev_dbg(&drv_data->pdev->dev, + "cr16 is 0x%x\n", read_STAT(drv_data)); + + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); while (drv_data->tx < drv_data->tx_end) { - write_TDBR(*(u16 *) (drv_data->tx)); - while ((read_STAT() & BIT_STAT_TXS)) - continue; + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + while ((read_STAT(drv_data) & BIT_STAT_TXS)) + cpu_relax(); drv_data->tx += 2; } - - /* poll for SPI completion before returning */ - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; } static void u16_cs_chg_writer(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + while (drv_data->tx < drv_data->tx_end) { - write_FLAG(chip->flag); - SSYNC(); - - write_TDBR(*(u16 *) (drv_data->tx)); - while ((read_STAT() & BIT_STAT_TXS)) - continue; - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; - write_FLAG(0xFF00 | chip->flag); - SSYNC(); - if (chip->cs_chg_udelay) - udelay(chip->cs_chg_udelay); + cs_active(drv_data, chip); + + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + while ((read_STAT(drv_data) & BIT_STAT_TXS)) + cpu_relax(); + + cs_deactive(drv_data, chip); + drv_data->tx += 2; } - write_FLAG(0xFF00); - SSYNC(); } static void u16_reader(struct driver_data *drv_data) { dev_dbg(&drv_data->pdev->dev, - "cr-16 is 0x%x\n", read_STAT()); - dummy_read(); + "cr-16 is 0x%x\n", read_STAT(drv_data)); + + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + + /* clear TDBR buffer before read(else it will be shifted out) */ + write_TDBR(drv_data, 0xFFFF); + + dummy_read(drv_data); while (drv_data->rx < (drv_data->rx_end - 2)) { - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - *(u16 *) (drv_data->rx) = read_RDBR(); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); drv_data->rx += 2; } - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - *(u16 *) (drv_data->rx) = read_SHAW(); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u16 *) (drv_data->rx) = read_SHAW(drv_data); drv_data->rx += 2; } @@ -464,36 +490,47 @@ static void u16_cs_chg_reader(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; - while (drv_data->rx < drv_data->rx_end) { - write_FLAG(chip->flag); - SSYNC(); - - read_RDBR(); /* kick off */ - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; - *(u16 *) (drv_data->rx) = read_SHAW(); - write_FLAG(0xFF00 | chip->flag); - SSYNC(); - if (chip->cs_chg_udelay) - udelay(chip->cs_chg_udelay); + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + + /* clear TDBR buffer before read(else it will be shifted out) */ + write_TDBR(drv_data, 0xFFFF); + + cs_active(drv_data, chip); + dummy_read(drv_data); + + while (drv_data->rx < drv_data->rx_end - 2) { + cs_deactive(drv_data, chip); + + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + cs_active(drv_data, chip); + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); drv_data->rx += 2; } - write_FLAG(0xFF00); - SSYNC(); + cs_deactive(drv_data, chip); + + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u16 *) (drv_data->rx) = read_SHAW(drv_data); + drv_data->rx += 2; } static void u16_duplex(struct driver_data *drv_data) { + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + /* in duplex mode, clk is triggered by writing of TDBR */ while (drv_data->tx < drv_data->tx_end) { - write_TDBR(*(u16 *) (drv_data->tx)); - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - *(u16 *) (drv_data->rx) = read_RDBR(); + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + while (read_STAT(drv_data) & BIT_STAT_TXS) + cpu_relax(); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); drv_data->rx += 2; drv_data->tx += 2; } @@ -503,25 +540,25 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); + while (drv_data->tx < drv_data->tx_end) { - write_FLAG(chip->flag); - SSYNC(); - - write_TDBR(*(u16 *) (drv_data->tx)); - while (!(read_STAT() & BIT_STAT_SPIF)) - continue; - while (!(read_STAT() & BIT_STAT_RXS)) - continue; - *(u16 *) (drv_data->rx) = read_RDBR(); - write_FLAG(0xFF00 | chip->flag); - SSYNC(); - if (chip->cs_chg_udelay) - udelay(chip->cs_chg_udelay); + cs_active(drv_data, chip); + + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + while (read_STAT(drv_data) & BIT_STAT_TXS) + cpu_relax(); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); + + cs_deactive(drv_data, chip); + drv_data->rx += 2; drv_data->tx += 2; } - write_FLAG(0xFF00); - SSYNC(); } /* test if ther is more transfer to be done */ @@ -546,6 +583,7 @@ static void *next_transfer(struct driver_data *drv_data) */ static void giveback(struct driver_data *drv_data) { + struct chip_data *chip = drv_data->cur_chip; struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; @@ -565,10 +603,13 @@ static void giveback(struct driver_data *drv_data) /* disable chip select signal. And not stop spi in autobuffer mode */ if (drv_data->tx_dma != 0xFFFF) { - write_FLAG(0xFF00); + cs_deactive(drv_data, chip); bfin_spi_disable(drv_data); } + if (!drv_data->cs_change) + cs_deactive(drv_data, chip); + if (msg->complete) msg->complete(msg->context); } @@ -576,14 +617,15 @@ static void giveback(struct driver_data *drv_data) static irqreturn_t dma_irq_handler(int irq, void *dev_id) { struct driver_data *drv_data = (struct driver_data *)dev_id; + struct chip_data *chip = drv_data->cur_chip; struct spi_message *msg = drv_data->cur_msg; dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n"); - clear_dma_irqstat(CH_SPI); + clear_dma_irqstat(drv_data->dma_channel); /* Wait for DMA to complete */ - while (get_dma_curr_irqstat(CH_SPI) & DMA_RUN) - continue; + while (get_dma_curr_irqstat(drv_data->dma_channel) & DMA_RUN) + cpu_relax(); /* * wait for the last transaction shifted out. HRM states: @@ -592,18 +634,19 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) * register until it goes low for 2 successive reads */ if (drv_data->tx != NULL) { - while ((bfin_read_SPI_STAT() & TXS) || - (bfin_read_SPI_STAT() & TXS)) - continue; + while ((read_STAT(drv_data) & TXS) || + (read_STAT(drv_data) & TXS)) + cpu_relax(); } - while (!(bfin_read_SPI_STAT() & SPIF)) - continue; - - bfin_spi_disable(drv_data); + while (!(read_STAT(drv_data) & SPIF)) + cpu_relax(); msg->actual_length += drv_data->len_in_bytes; + if (drv_data->cs_change) + cs_deactive(drv_data, chip); + /* Move to next transfer */ msg->state = next_transfer(drv_data); @@ -613,8 +656,8 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) /* free the irq handler before next transfer */ dev_dbg(&drv_data->pdev->dev, "disable dma channel irq%d\n", - CH_SPI); - dma_disable_irq(CH_SPI); + drv_data->dma_channel); + dma_disable_irq(drv_data->dma_channel); return IRQ_HANDLED; } @@ -690,31 +733,67 @@ static void pump_transfers(unsigned long data) drv_data->rx_dma = transfer->rx_dma; drv_data->tx_dma = transfer->tx_dma; drv_data->len_in_bytes = transfer->len; + drv_data->cs_change = transfer->cs_change; + + /* Bits per word setup */ + switch (transfer->bits_per_word) { + case 8: + drv_data->n_bytes = 1; + width = CFG_SPI_WORDSIZE8; + drv_data->read = chip->cs_change_per_word ? + u8_cs_chg_reader : u8_reader; + drv_data->write = chip->cs_change_per_word ? + u8_cs_chg_writer : u8_writer; + drv_data->duplex = chip->cs_change_per_word ? + u8_cs_chg_duplex : u8_duplex; + break; + + case 16: + drv_data->n_bytes = 2; + width = CFG_SPI_WORDSIZE16; + drv_data->read = chip->cs_change_per_word ? + u16_cs_chg_reader : u16_reader; + drv_data->write = chip->cs_change_per_word ? + u16_cs_chg_writer : u16_writer; + drv_data->duplex = chip->cs_change_per_word ? + u16_cs_chg_duplex : u16_duplex; + break; + + default: + /* No change, the same as default setting */ + drv_data->n_bytes = chip->n_bytes; + width = chip->width; + drv_data->write = drv_data->tx ? chip->write : null_writer; + drv_data->read = drv_data->rx ? chip->read : null_reader; + drv_data->duplex = chip->duplex ? chip->duplex : null_writer; + break; + } + cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); + cr |= (width << 8); + write_CTRL(drv_data, cr); - width = chip->width; if (width == CFG_SPI_WORDSIZE16) { drv_data->len = (transfer->len) >> 1; } else { drv_data->len = transfer->len; } - drv_data->write = drv_data->tx ? chip->write : null_writer; - drv_data->read = drv_data->rx ? chip->read : null_reader; - drv_data->duplex = chip->duplex ? chip->duplex : null_writer; - dev_dbg(&drv_data->pdev->dev, - "transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n", - drv_data->write, chip->write, null_writer); + dev_dbg(&drv_data->pdev->dev, "transfer: ", + "drv_data->write is %p, chip->write is %p, null_wr is %p\n", + drv_data->write, chip->write, null_writer); /* speed and width has been set on per message */ message->state = RUNNING_STATE; dma_config = 0; - /* restore spi status for each spi transfer */ - if (transfer->speed_hz) { - write_BAUD(hz_to_spi_baud(transfer->speed_hz)); - } else { - write_BAUD(chip->baud); - } - write_FLAG(chip->flag); + /* Speed setup (surely valid because already checked) */ + if (transfer->speed_hz) + write_BAUD(drv_data, hz_to_spi_baud(transfer->speed_hz)); + else + write_BAUD(drv_data, chip->baud); + + write_STAT(drv_data, BIT_STAT_CLR); + cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); + cs_active(drv_data, chip); dev_dbg(&drv_data->pdev->dev, "now pumping a transfer: width is %d, len is %d\n", @@ -727,25 +806,25 @@ static void pump_transfers(unsigned long data) */ if (drv_data->cur_chip->enable_dma && drv_data->len > 6) { - write_STAT(BIT_STAT_CLR); - disable_dma(CH_SPI); - clear_dma_irqstat(CH_SPI); + disable_dma(drv_data->dma_channel); + clear_dma_irqstat(drv_data->dma_channel); bfin_spi_disable(drv_data); /* config dma channel */ dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n"); if (width == CFG_SPI_WORDSIZE16) { - set_dma_x_count(CH_SPI, drv_data->len); - set_dma_x_modify(CH_SPI, 2); + set_dma_x_count(drv_data->dma_channel, drv_data->len); + set_dma_x_modify(drv_data->dma_channel, 2); dma_width = WDSIZE_16; } else { - set_dma_x_count(CH_SPI, drv_data->len); - set_dma_x_modify(CH_SPI, 1); + set_dma_x_count(drv_data->dma_channel, drv_data->len); + set_dma_x_modify(drv_data->dma_channel, 1); dma_width = WDSIZE_8; } - /* set transfer width,direction. And enable spi */ - cr = (read_CTRL() & (~BIT_CTL_TIMOD)); + /* poll for SPI completion before start */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); /* dirty hack for autobuffer DMA mode */ if (drv_data->tx_dma == 0xFFFF) { @@ -755,13 +834,18 @@ static void pump_transfers(unsigned long data) /* no irq in autobuffer mode */ dma_config = (DMAFLOW_AUTO | RESTART | dma_width | DI_EN); - set_dma_config(CH_SPI, dma_config); - set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx); - enable_dma(CH_SPI); - write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) | - (CFG_SPI_ENABLE << 14)); - - /* just return here, there can only be one transfer in this mode */ + set_dma_config(drv_data->dma_channel, dma_config); + set_dma_start_addr(drv_data->dma_channel, + (unsigned long)drv_data->tx); + enable_dma(drv_data->dma_channel); + + /* start SPI transfer */ + write_CTRL(drv_data, + (cr | CFG_SPI_DMAWRITE | BIT_CTL_ENABLE)); + + /* just return here, there can only be one transfer + * in this mode + */ message->status = 0; giveback(drv_data); return; @@ -772,58 +856,51 @@ static void pump_transfers(unsigned long data) /* set transfer mode, and enable SPI */ dev_dbg(&drv_data->pdev->dev, "doing DMA in.\n"); - /* disable SPI before write to TDBR */ - write_CTRL(cr & ~BIT_CTL_ENABLE); - /* clear tx reg soformer data is not shifted out */ - write_TDBR(0xFF); + write_TDBR(drv_data, 0xFFFF); - set_dma_x_count(CH_SPI, drv_data->len); + set_dma_x_count(drv_data->dma_channel, drv_data->len); /* start dma */ - dma_enable_irq(CH_SPI); + dma_enable_irq(drv_data->dma_channel); dma_config = (WNR | RESTART | dma_width | DI_EN); - set_dma_config(CH_SPI, dma_config); - set_dma_start_addr(CH_SPI, (unsigned long)drv_data->rx); - enable_dma(CH_SPI); + set_dma_config(drv_data->dma_channel, dma_config); + set_dma_start_addr(drv_data->dma_channel, + (unsigned long)drv_data->rx); + enable_dma(drv_data->dma_channel); + + /* start SPI transfer */ + write_CTRL(drv_data, + (cr | CFG_SPI_DMAREAD | BIT_CTL_ENABLE)); - cr |= - CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE << - 14); - /* set transfer mode, and enable SPI */ - write_CTRL(cr); } else if (drv_data->tx != NULL) { dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n"); /* start dma */ - dma_enable_irq(CH_SPI); + dma_enable_irq(drv_data->dma_channel); dma_config = (RESTART | dma_width | DI_EN); - set_dma_config(CH_SPI, dma_config); - set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx); - enable_dma(CH_SPI); - - write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) | - (CFG_SPI_ENABLE << 14)); - + set_dma_config(drv_data->dma_channel, dma_config); + set_dma_start_addr(drv_data->dma_channel, + (unsigned long)drv_data->tx); + enable_dma(drv_data->dma_channel); + + /* start SPI transfer */ + write_CTRL(drv_data, + (cr | CFG_SPI_DMAWRITE | BIT_CTL_ENABLE)); } } else { /* IO mode write then read */ dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); - write_STAT(BIT_STAT_CLR); - if (drv_data->tx != NULL && drv_data->rx != NULL) { /* full duplex mode */ BUG_ON((drv_data->tx_end - drv_data->tx) != (drv_data->rx_end - drv_data->rx)); - cr = (read_CTRL() & (~BIT_CTL_TIMOD)); - cr |= CFG_SPI_WRITE | (width << 8) | - (CFG_SPI_ENABLE << 14); dev_dbg(&drv_data->pdev->dev, "IO duplex: cr is 0x%x\n", cr); - write_CTRL(cr); - SSYNC(); + /* set SPI transfer mode */ + write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); drv_data->duplex(drv_data); @@ -831,14 +908,11 @@ static void pump_transfers(unsigned long data) tranf_success = 0; } else if (drv_data->tx != NULL) { /* write only half duplex */ - cr = (read_CTRL() & (~BIT_CTL_TIMOD)); - cr |= CFG_SPI_WRITE | (width << 8) | - (CFG_SPI_ENABLE << 14); - dev_dbg(&drv_data->pdev->dev, + dev_dbg(&drv_data->pdev->dev, "IO write: cr is 0x%x\n", cr); - write_CTRL(cr); - SSYNC(); + /* set SPI transfer mode */ + write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); drv_data->write(drv_data); @@ -846,14 +920,11 @@ static void pump_transfers(unsigned long data) tranf_success = 0; } else if (drv_data->rx != NULL) { /* read only half duplex */ - cr = (read_CTRL() & (~BIT_CTL_TIMOD)); - cr |= CFG_SPI_READ | (width << 8) | - (CFG_SPI_ENABLE << 14); - dev_dbg(&drv_data->pdev->dev, + dev_dbg(&drv_data->pdev->dev, "IO read: cr is 0x%x\n", cr); - write_CTRL(cr); - SSYNC(); + /* set SPI transfer mode */ + write_CTRL(drv_data, (cr | CFG_SPI_READ)); drv_data->read(drv_data); if (drv_data->rx != drv_data->rx_end) @@ -861,7 +932,7 @@ static void pump_transfers(unsigned long data) } if (!tranf_success) { - dev_dbg(&drv_data->pdev->dev, + dev_dbg(&drv_data->pdev->dev, "IO write error!\n"); message->state = ERROR_STATE; } else { @@ -881,9 +952,11 @@ static void pump_transfers(unsigned long data) /* pop a msg from queue and kick off real transfer */ static void pump_messages(struct work_struct *work) { - struct driver_data *drv_data = container_of(work, struct driver_data, pump_messages); + struct driver_data *drv_data; unsigned long flags; + drv_data = container_of(work, struct driver_data, pump_messages); + /* Lock queue and check for queue work */ spin_lock_irqsave(&drv_data->lock, flags); if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) { @@ -902,6 +975,14 @@ static void pump_messages(struct work_struct *work) /* Extract head of queue */ drv_data->cur_msg = list_entry(drv_data->queue.next, struct spi_message, queue); + + /* Setup the SSP using the per chip configuration */ + drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); + if (restore_state(drv_data)) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return; + }; + list_del_init(&drv_data->cur_msg->queue); /* Initial message state */ @@ -909,15 +990,12 @@ static void pump_messages(struct work_struct *work) drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, struct spi_transfer, transfer_list); - /* Setup the SSP using the per chip configuration */ - drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); - restore_state(drv_data); + dev_dbg(&drv_data->pdev->dev, "got a message to pump, " + "state is set to: baud %d, flag 0x%x, ctl 0x%x\n", + drv_data->cur_chip->baud, drv_data->cur_chip->flag, + drv_data->cur_chip->ctl_reg); + dev_dbg(&drv_data->pdev->dev, - "got a message to pump, state is set to: baud %d, flag 0x%x, ctl 0x%x\n", - drv_data->cur_chip->baud, drv_data->cur_chip->flag, - drv_data->cur_chip->ctl_reg); - - dev_dbg(&drv_data->pdev->dev, "the first transfer len is %d\n", drv_data->cur_transfer->len); @@ -959,6 +1037,22 @@ static int transfer(struct spi_device *spi, struct spi_message *msg) return 0; } +#define MAX_SPI_SSEL 7 + +static u16 ssel[3][MAX_SPI_SSEL] = { + {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3, + P_SPI0_SSEL4, P_SPI0_SSEL5, + P_SPI0_SSEL6, P_SPI0_SSEL7}, + + {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3, + P_SPI1_SSEL4, P_SPI1_SSEL5, + P_SPI1_SSEL6, P_SPI1_SSEL7}, + + {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3, + P_SPI2_SSEL4, P_SPI2_SSEL5, + P_SPI2_SSEL6, P_SPI2_SSEL7}, +}; + /* first setup for new devices */ static int setup(struct spi_device *spi) { @@ -993,6 +1087,18 @@ static int setup(struct spi_device *spi) /* chip_info isn't always needed */ if (chip_info) { + /* Make sure people stop trying to set fields via ctl_reg + * when they should actually be using common SPI framework. + * Currently we let through: WOM EMISO PSSE GM SZ TIMOD. + * Not sure if a user actually needs/uses any of these, + * but let's assume (for now) they do. + */ + if (chip_info->ctl_reg & (SPE|MSTR|CPOL|CPHA|LSBF|SIZE)) { + dev_err(&spi->dev, "do not set bits in ctl_reg " + "that the SPI framework manages\n"); + return -EINVAL; + } + chip->enable_dma = chip_info->enable_dma != 0 && drv_data->master_info->enable_dma; chip->ctl_reg = chip_info->ctl_reg; @@ -1015,20 +1121,20 @@ static int setup(struct spi_device *spi) * if any one SPI chip is registered and wants DMA, request the * DMA channel for it */ - if (chip->enable_dma && !dma_requested) { + if (chip->enable_dma && !drv_data->dma_requested) { /* register dma irq handler */ - if (request_dma(CH_SPI, "BF53x_SPI_DMA") < 0) { + if (request_dma(drv_data->dma_channel, "BF53x_SPI_DMA") < 0) { dev_dbg(&spi->dev, "Unable to request BlackFin SPI DMA channel\n"); return -ENODEV; } - if (set_dma_callback(CH_SPI, (void *)dma_irq_handler, drv_data) - < 0) { + if (set_dma_callback(drv_data->dma_channel, + (void *)dma_irq_handler, drv_data) < 0) { dev_dbg(&spi->dev, "Unable to set dma callback\n"); return -EPERM; } - dma_disable_irq(CH_SPI); - dma_requested = 1; + dma_disable_irq(drv_data->dma_channel); + drv_data->dma_requested = 1; } /* @@ -1077,6 +1183,14 @@ static int setup(struct spi_device *spi) spi_set_ctldata(spi, chip); + dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num); + if ((chip->chip_select_num > 0) + && (chip->chip_select_num <= spi->master->num_chipselect)) + peripheral_request(ssel[spi->master->bus_num] + [chip->chip_select_num-1], DRV_NAME); + + cs_deactive(drv_data, chip); + return 0; } @@ -1088,6 +1202,11 @@ static void cleanup(struct spi_device *spi) { struct chip_data *chip = spi_get_ctldata(spi); + if ((chip->chip_select_num > 0) + && (chip->chip_select_num <= spi->master->num_chipselect)) + peripheral_free(ssel[spi->master->bus_num] + [chip->chip_select_num-1]); + kfree(chip); } @@ -1183,6 +1302,7 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev) struct bfin5xx_spi_master *platform_info; struct spi_master *master; struct driver_data *drv_data = 0; + struct resource *res; int status = 0; platform_info = dev->platform_data; @@ -1193,10 +1313,12 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev) dev_err(&pdev->dev, "can not alloc spi_master\n"); return -ENOMEM; } + drv_data = spi_master_get_devdata(master); drv_data->master = master; drv_data->master_info = platform_info; drv_data->pdev = pdev; + drv_data->pin_req = platform_info->pin_req; master->bus_num = pdev->id; master->num_chipselect = platform_info->num_chipselect; @@ -1204,15 +1326,38 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev) master->setup = setup; master->transfer = transfer; + /* Find and map our resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(dev, "Cannot get IORESOURCE_MEM\n"); + status = -ENOENT; + goto out_error_get_res; + } + + drv_data->regs_base = ioremap(res->start, (res->end - res->start + 1)); + if (drv_data->regs_base == NULL) { + dev_err(dev, "Cannot map IO\n"); + status = -ENXIO; + goto out_error_ioremap; + } + + drv_data->dma_channel = platform_get_irq(pdev, 0); + if (drv_data->dma_channel < 0) { + dev_err(dev, "No DMA channel specified\n"); + status = -ENOENT; + goto out_error_no_dma_ch; + } + /* Initial and start queue */ status = init_queue(drv_data); if (status != 0) { - dev_err(&pdev->dev, "problem initializing queue\n"); + dev_err(dev, "problem initializing queue\n"); goto out_error_queue_alloc; } + status = start_queue(drv_data); if (status != 0) { - dev_err(&pdev->dev, "problem starting queue\n"); + dev_err(dev, "problem starting queue\n"); goto out_error_queue_alloc; } @@ -1220,15 +1365,30 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drv_data); status = spi_register_master(master); if (status != 0) { - dev_err(&pdev->dev, "problem registering spi master\n"); + dev_err(dev, "problem registering spi master\n"); goto out_error_queue_alloc; } - dev_dbg(&pdev->dev, "controller probe successfully\n"); + + status = peripheral_request_list(drv_data->pin_req, DRV_NAME); + if (status != 0) { + dev_err(&pdev->dev, ": Requesting Peripherals failed\n"); + goto out_error; + } + + dev_info(dev, "%s, Version %s, regs_base@%p, dma channel@%d\n", + DRV_DESC, DRV_VERSION, drv_data->regs_base, + drv_data->dma_channel); return status; - out_error_queue_alloc: +out_error_queue_alloc: destroy_queue(drv_data); +out_error_no_dma_ch: + iounmap((void *) drv_data->regs_base); +out_error_ioremap: +out_error_get_res: +out_error: spi_master_put(master); + return status; } @@ -1251,13 +1411,15 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev) /* Release DMA */ if (drv_data->master_info->enable_dma) { - if (dma_channel_active(CH_SPI)) - free_dma(CH_SPI); + if (dma_channel_active(drv_data->dma_channel)) + free_dma(drv_data->dma_channel); } /* Disconnect from the SPI framework */ spi_unregister_master(drv_data->master); + peripheral_free_list(drv_data->pin_req); + /* Prevent double remove */ platform_set_drvdata(pdev, NULL); @@ -1305,7 +1467,7 @@ static int bfin5xx_spi_resume(struct platform_device *pdev) MODULE_ALIAS("bfin-spi-master"); /* for platform bus hotplug */ static struct platform_driver bfin5xx_spi_driver = { .driver = { - .name = "bfin-spi-master", + .name = DRV_NAME, .owner = THIS_MODULE, }, .suspend = bfin5xx_spi_suspend, |