Merge remote-tracking branches 'spi/topic/adi-v3', 'spi/topic/atmel', 'spi/topic...
[sfrench/cifs-2.6.git] / drivers / spi / spi-s3c64xx.c
index b1e26f00cd05c8cee383e1843ed5bf6795776e7b..1c36311935d7cb271ce0287166f224dc84c046e9 100644 (file)
@@ -773,14 +773,6 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
                return ERR_PTR(-ENOMEM);
        }
 
-       cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
-       if (!gpio_is_valid(cs->line)) {
-               dev_err(&spi->dev, "chip select gpio is not specified or invalid\n");
-               kfree(cs);
-               of_node_put(data_np);
-               return ERR_PTR(-EINVAL);
-       }
-
        of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay);
        cs->fb_delay = fb_delay;
        of_node_put(data_np);
@@ -801,9 +793,16 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        int err;
 
        sdd = spi_master_get_devdata(spi->master);
-       if (!cs && spi->dev.of_node) {
+       if (spi->dev.of_node) {
                cs = s3c64xx_get_slave_ctrldata(spi);
                spi->controller_data = cs;
+       } else if (cs) {
+               /* On non-DT platforms the SPI core will set spi->cs_gpio
+                * to -ENOENT. The GPIO pin used to drive the chip select
+                * is defined by using platform data so spi->cs_gpio value
+                * has to be override to have the proper GPIO pin number.
+                */
+               spi->cs_gpio = cs->line;
        }
 
        if (IS_ERR_OR_NULL(cs)) {
@@ -812,17 +811,17 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        }
 
        if (!spi_get_ctldata(spi)) {
-               err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH,
-                                      dev_name(&spi->dev));
-               if (err) {
-                       dev_err(&spi->dev,
-                               "Failed to get /CS gpio [%d]: %d\n",
-                               cs->line, err);
-                       goto err_gpio_req;
+               if (gpio_is_valid(spi->cs_gpio)) {
+                       err = gpio_request_one(spi->cs_gpio, GPIOF_OUT_INIT_HIGH,
+                                              dev_name(&spi->dev));
+                       if (err) {
+                               dev_err(&spi->dev,
+                                       "Failed to get /CS gpio [%d]: %d\n",
+                                       spi->cs_gpio, err);
+                               goto err_gpio_req;
+                       }
                }
 
-               spi->cs_gpio = cs->line;
-
                spi_set_ctldata(spi, cs);
        }
 
@@ -875,7 +874,8 @@ setup_exit:
        /* setup() returns with device de-selected */
        writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
 
-       gpio_free(cs->line);
+       if (gpio_is_valid(spi->cs_gpio))
+               gpio_free(spi->cs_gpio);
        spi_set_ctldata(spi, NULL);
 
 err_gpio_req:
@@ -889,11 +889,20 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi)
 {
        struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi);
 
-       if (cs) {
+       if (gpio_is_valid(spi->cs_gpio)) {
                gpio_free(spi->cs_gpio);
                if (spi->dev.of_node)
                        kfree(cs);
+               else {
+                       /* On non-DT platforms, the SPI core sets
+                        * spi->cs_gpio to -ENOENT and .setup()
+                        * overrides it with the GPIO pin value
+                        * passed using platform data.
+                        */
+                       spi->cs_gpio = -ENOENT;
+               }
        }
+
        spi_set_ctldata(spi, NULL);
 }