]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/spi/spi_bfin5xx.c
spi: fix platform driver hotplug/coldplug
[linux-2.6-omap-h63xx.git] / drivers / spi / spi_bfin5xx.c
index 22697b812205725829ae33f2fbf7308604834b2f..a9ac1fdb30948c5eba8ff864d0ee156d8db7e247 100644 (file)
@@ -1,37 +1,11 @@
 /*
- * 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 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)
+ * Blackfin On-Chip SPI Driver
  *
  * 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
- * the Free Software Foundation ;  either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ;  without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Enter bugs at http://blackfin.uclinux.org/
  *
- * You should have received a copy of the GNU General Public License
- * along with this program ;  see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/init.h>
@@ -54,7 +28,7 @@
 
 #define DRV_NAME       "bfin-spi"
 #define DRV_AUTHOR     "Bryan Wu, Luke Yang"
-#define DRV_DESC       "Blackfin BF5xx on-chip SPI Contoller Driver"
+#define DRV_DESC       "Blackfin BF5xx on-chip SPI Controller Driver"
 #define DRV_VERSION    "1.0"
 
 MODULE_AUTHOR(DRV_AUTHOR);
@@ -223,10 +197,9 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
 #define MAX_SPI_SSEL   7
 
 /* stop controller and re-config current chip*/
-static int restore_state(struct driver_data *drv_data)
+static void 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(drv_data, BIT_STAT_CLR);
@@ -239,13 +212,6 @@ static int restore_state(struct driver_data *drv_data)
 
        bfin_spi_enable(drv_data);
        cs_active(drv_data, chip);
-
-       if (ret)
-               dev_dbg(&drv_data->pdev->dev,
-                       ": request chip select number %d failed\n",
-                       chip->chip_select_num);
-
-       return ret;
 }
 
 /* used to kick off transfer in rx mode */
@@ -286,32 +252,30 @@ static void u8_writer(struct driver_data *drv_data)
        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(drv_data, (*(u8 *) (drv_data->tx)));
                while (read_STAT(drv_data) & BIT_STAT_TXS)
                        cpu_relax();
                ++drv_data->tx;
        }
+
+       /* poll for SPI completion before return */
+       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+               cpu_relax();
 }
 
 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) {
                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_SPIF))
+                       cpu_relax();
 
                cs_deactive(drv_data, chip);
 
@@ -350,43 +314,28 @@ static void u8_cs_chg_reader(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();
-
-       /* clear TDBR buffer before read(else it will be shifted out) */
-       write_TDBR(drv_data, 0xFFFF);
+       while (drv_data->rx < drv_data->rx_end) {
+               cs_active(drv_data, chip);
+               read_RDBR(drv_data);    /* kick off */
 
-       cs_active(drv_data, chip);
-       dummy_read(drv_data);
+               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+                       cpu_relax();
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+                       cpu_relax();
 
-       while (drv_data->rx < drv_data->rx_end - 1) {
+               *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
                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;
        }
-       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(drv_data, (*(u8 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -400,15 +349,12 @@ 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) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -426,32 +372,30 @@ static void u16_writer(struct driver_data *drv_data)
        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(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 return */
+       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+               cpu_relax();
 }
 
 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) {
                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_SPIF))
+                       cpu_relax();
 
                cs_deactive(drv_data, chip);
 
@@ -519,14 +463,10 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
 
 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(drv_data, (*(u16 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -540,15 +480,11 @@ 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) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -616,7 +552,7 @@ 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 driver_data *drv_data = dev_id;
        struct chip_data *chip = drv_data->cur_chip;
        struct spi_message *msg = drv_data->cur_msg;
 
@@ -777,8 +713,8 @@ static void pump_transfers(unsigned long data)
        } else {
                drv_data->len = transfer->len;
        }
-       dev_dbg(&drv_data->pdev->dev, "transfer: ",
-               "drv_data->write is %p, chip->write is %p, null_wr is %p\n",
+       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 */
@@ -978,10 +914,7 @@ static void pump_messages(struct work_struct *work)
 
        /* 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;
-       };
+       restore_state(drv_data);
 
        list_del_init(&drv_data->cur_msg->queue);
 
@@ -1187,7 +1120,7 @@ static int setup(struct spi_device *spi)
        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);
+                       [chip->chip_select_num-1], spi->modalias);
 
        cs_deactive(drv_data, chip);
 
@@ -1361,6 +1294,12 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
                goto out_error_queue_alloc;
        }
 
+       status = peripheral_request_list(drv_data->pin_req, DRV_NAME);
+       if (status != 0) {
+               dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
+               goto out_error_queue_alloc;
+       }
+
        /* Register with the SPI framework */
        platform_set_drvdata(pdev, drv_data);
        status = spi_register_master(master);
@@ -1369,12 +1308,6 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
                goto out_error_queue_alloc;
        }
 
-       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);
@@ -1386,7 +1319,6 @@ 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;
@@ -1464,7 +1396,7 @@ static int bfin5xx_spi_resume(struct platform_device *pdev)
 #define bfin5xx_spi_resume NULL
 #endif                         /* CONFIG_PM */
 
-MODULE_ALIAS("bfin-spi-master");       /* for platform bus hotplug */
+MODULE_ALIAS("platform:bfin-spi");
 static struct platform_driver bfin5xx_spi_driver = {
        .driver = {
                .name   = DRV_NAME,