#include <linux/clk.h>
 
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/dm9000.h>
 #include <linux/leds.h>
 #include <linux/platform_data/rtc-v3020.h>
 #define LCD_SPI_BUS_NUM        (1)
 
 static struct spi_gpio_platform_data cm_x300_spi_gpio_pdata = {
-       .sck            = GPIO_LCD_SCL,
-       .mosi           = GPIO_LCD_DIN,
-       .miso           = GPIO_LCD_DOUT,
        .num_chipselect = 1,
 };
 
        },
 };
 
+static struct gpiod_lookup_table cm_x300_spi_gpiod_table = {
+       .dev_id         = "spi_gpio",
+       .table          = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_LCD_SCL,
+                           "sck", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DIN,
+                           "mosi", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DOUT,
+                           "miso", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio-pxa", GPIO_LCD_CS,
+                           "cs", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct tdo24m_platform_data cm_x300_tdo24m_pdata = {
        .model = TDO35S,
 };
                .max_speed_hz           = 1000000,
                .bus_num                = LCD_SPI_BUS_NUM,
                .chip_select            = 0,
-               .controller_data        = (void *) GPIO_LCD_CS,
                .platform_data          = &cm_x300_tdo24m_pdata,
        },
 };
 {
        spi_register_board_info(cm_x300_spi_devices,
                                ARRAY_SIZE(cm_x300_spi_devices));
+       gpiod_add_lookup_table(&cm_x300_spi_gpiod_table);
        platform_device_register(&cm_x300_spi_gpio);
 }
 #else
 
  */
 
 static struct spi_gpio_platform_data raumfeld_spi_platform_data = {
-       .sck            = GPIO_SPI_CLK,
-       .mosi           = GPIO_SPI_MOSI,
-       .miso           = GPIO_SPI_MISO,
        .num_chipselect = 3,
 };
 
        }
 };
 
+static struct gpiod_lookup_table raumfeld_spi_gpiod_table = {
+       .dev_id         = "spi_gpio",
+       .table          = {
+               GPIO_LOOKUP("gpio-0", GPIO_SPI_CLK,
+                           "sck", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio-0", GPIO_SPI_MOSI,
+                           "mosi", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio-0", GPIO_SPI_MISO,
+                           "miso", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("gpio-0", GPIO_SPDIF_CS,
+                               "cs", 0, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("gpio-0", GPIO_ACCEL_CS,
+                               "cs", 1, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("gpio-0", GPIO_MCLK_DAC_CS,
+                               "cs", 2, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct lis3lv02d_platform_data lis3_pdata = {
        .click_flags    = LIS3_CLICK_SINGLE_X |
                          LIS3_CLICK_SINGLE_Y |
        .max_speed_hz   = 10000,                \
        .bus_num        = 0,                    \
        .chip_select    = 0,                    \
-       .controller_data = (void *) GPIO_SPDIF_CS,      \
 }
 
 #define SPI_LIS3       \
        .max_speed_hz   = 1000000,              \
        .bus_num        = 0,                    \
        .chip_select    = 1,                    \
-       .controller_data = (void *) GPIO_ACCEL_CS,      \
        .platform_data  = &lis3_pdata,          \
        .irq            = PXA_GPIO_TO_IRQ(GPIO_ACCEL_IRQ),      \
 }
        .max_speed_hz   = 1000000,              \
        .bus_num        = 0,                    \
        .chip_select    = 2,                    \
-       .controller_data = (void *) GPIO_MCLK_DAC_CS,   \
 }
 
 static struct spi_board_info connector_spi_devices[] __initdata = {
        else
                gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0);
 
+       gpiod_add_lookup_table(&raumfeld_spi_gpiod_table);
        platform_add_devices(ARRAY_AND_SIZE(raumfeld_common_devices));
        i2c_register_board_info(1, &raumfeld_pwri2c_board_info, 1);
 }
 
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/syscore_ops.h>
 #include <linux/serial_core.h>
 #include <linux/serial_s3c.h>
 /* LCD SPI support */
 
 static struct spi_gpio_platform_data jive_lcd_spi = {
-       .sck            = S3C2410_GPG(8),
-       .mosi           = S3C2410_GPB(8),
-       .miso           = SPI_GPIO_NO_MISO,
+       .num_chipselect = 1,
 };
 
 static struct platform_device jive_device_lcdspi = {
-       .name           = "spi-gpio",
+       .name           = "spi_gpio",
        .id             = 1,
        .dev.platform_data = &jive_lcd_spi,
 };
 
+static struct gpiod_lookup_table jive_lcdspi_gpiod_table = {
+       .dev_id         = "spi_gpio",
+       .table          = {
+               GPIO_LOOKUP("GPIOG", 8,
+                           "sck", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOB", 8,
+                           "mosi", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOB", 7,
+                           "cs", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
 
 /* WM8750 audio code SPI definition */
 
 static struct spi_gpio_platform_data jive_wm8750_spi = {
-       .sck            = S3C2410_GPB(4),
-       .mosi           = S3C2410_GPB(9),
-       .miso           = SPI_GPIO_NO_MISO,
+       .num_chipselect = 1,
 };
 
 static struct platform_device jive_device_wm8750 = {
-       .name           = "spi-gpio",
+       .name           = "spi_gpio",
        .id             = 2,
        .dev.platform_data = &jive_wm8750_spi,
 };
 
+static struct gpiod_lookup_table jive_wm8750_gpiod_table = {
+       .dev_id         = "spi_gpio",
+       .table          = {
+               GPIO_LOOKUP("GPIOB", 4,
+                           "gpio-sck", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOB", 9,
+                           "gpio-mosi", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOH", 10,
+                           "cs", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 /* JIVE SPI devices. */
 
 static struct spi_board_info __initdata jive_spi_devs[] = {
                .mode           = SPI_MODE_3,   /* CPOL=1, CPHA=1 */
                .max_speed_hz   = 100000,
                .platform_data  = &jive_lcm_config,
-               .controller_data = (void *)S3C2410_GPB(7),
        }, {
                .modalias       = "WM8750",
                .bus_num        = 2,
                .chip_select    = 0,
                .mode           = SPI_MODE_0,   /* CPOL=0, CPHA=0 */
                .max_speed_hz   = 100000,
-               .controller_data = (void *)S3C2410_GPH(10),
        },
 };
 
        /** TODO - check that this is after the cmdline option! */
        s3c_nand_set_platdata(&jive_nand_info);
 
-       /* initialise the spi */
-
        gpio_request(S3C2410_GPG(13), "lcm reset");
        gpio_direction_output(S3C2410_GPG(13), 0);
 
-       gpio_request(S3C2410_GPB(7), "jive spi");
-       gpio_direction_output(S3C2410_GPB(7), 1);
-
        gpio_request_one(S3C2410_GPB(6), GPIOF_OUT_INIT_LOW, NULL);
        gpio_free(S3C2410_GPB(6));
 
-       gpio_request_one(S3C2410_GPG(8), GPIOF_OUT_INIT_HIGH, NULL);
-       gpio_free(S3C2410_GPG(8));
-
-       /* initialise the WM8750 spi */
-
-       gpio_request(S3C2410_GPH(10), "jive wm8750 spi");
-       gpio_direction_output(S3C2410_GPH(10), 1);
-
        /* Turn off suspend on both USB ports, and switch the
         * selectable USB port to USB device mode. */
 
 
        pm_power_off = jive_power_off;
 
+       gpiod_add_lookup_table(&jive_lcdspi_gpiod_table);
+       gpiod_add_lookup_table(&jive_wm8750_gpiod_table);
        platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices));
 }
 
 
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 /* SPI */
 
 static struct spi_gpio_platform_data spi_gpio_cfg = {
-       .sck            = S3C2410_GPG(7),
-       .mosi           = S3C2410_GPG(6),
-       .miso           = S3C2410_GPG(5),
+       .num_chipselect = 1,
 };
 
 static struct platform_device qt2410_spi = {
-       .name           = "spi-gpio",
+       .name           = "spi_gpio",
        .id             = 1,
        .dev.platform_data = &spi_gpio_cfg,
 };
 
+static struct gpiod_lookup_table qt2410_spi_gpiod_table = {
+       .dev_id         = "spi_gpio",
+       .table          = {
+               GPIO_LOOKUP("GPIOG", 7,
+                           "sck", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOG", 6,
+                           "mosi", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOG", 5,
+                           "miso", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOB", 5,
+                           "cs", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 /* Board devices */
 
 static struct platform_device *qt2410_devices[] __initdata = {
        s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
        s3c_i2c0_set_platdata(NULL);
 
-       WARN_ON(gpio_request(S3C2410_GPB(5), "spi cs"));
-       gpio_direction_output(S3C2410_GPB(5), 1);
-
+       gpiod_add_lookup_table(&qt2410_spi_gpiod_table);
        platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices));
        s3c_pm_init();
 }
 
 
 /* GPM0 -> CS */
 static struct spi_gpio_platform_data smartq_lcd_control = {
-       .sck                    = S3C64XX_GPM(1),
-       .mosi                   = S3C64XX_GPM(2),
-       .miso                   = S3C64XX_GPM(2),
+       .num_chipselect = 1,
 };
 
 static struct platform_device smartq_lcd_control_device = {
-       .name                   = "spi-gpio",
+       .name                   = "spi_gpio",
        .id                     = 1,
        .dev.platform_data      = &smartq_lcd_control,
 };
 
+static struct gpiod_lookup_table smartq_lcd_control_gpiod_table = {
+       .dev_id         = "spi_gpio",
+       .table          = {
+               GPIO_LOOKUP("GPIOM", 1,
+                           "sck", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOM", 2,
+                           "mosi", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOM", 3,
+                           "miso", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOM", 0,
+                           "cs", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void smartq_lcd_power_set(struct plat_lcd_data *pd, unsigned int power)
 {
        gpio_direction_output(S3C64XX_GPM(3), power);
        WARN_ON(smartq_wifi_init());
 
        pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup));
+       gpiod_add_lookup_table(&smartq_lcd_control_gpiod_table);
        platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices));
 
        gpiod_add_lookup_table(&smartq_audio_gpios);
 
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/leds.h>
 };
 
 static struct spi_gpio_platform_data db1100_spictl_pd = {
-       .sck            = 209,
-       .mosi           = 208,
-       .miso           = 207,
        .num_chipselect = 1,
 };
 
                .mode            = 0,
                .irq             = AU1100_GPIO21_INT,
                .platform_data   = &db1100_touch_pd,
-               .controller_data = (void *)210, /* for spi_gpio: CS# GPIO210 */
        },
 };
 
        },
 };
 
+/*
+ * Alchemy GPIO 2 has its base at 200 so the GPIO lines
+ * 207 thru 210 are GPIOs at offset 7 thru 10 at this chip.
+ */
+static struct gpiod_lookup_table db1100_spi_gpiod_table = {
+       .dev_id         = "spi_gpio",
+       .table          = {
+               GPIO_LOOKUP("alchemy-gpio2", 9,
+                           "sck", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("alchemy-gpio2", 8,
+                           "mosi", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("alchemy-gpio2", 7,
+                           "miso", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("alchemy-gpio2", 10,
+                           "cs", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
 
 static struct platform_device *db1x00_devs[] = {
        &db1x00_codec_dev,
                        clk_put(p);
 
                platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs));
+               gpiod_add_lookup_table(&db1100_spi_gpiod_table);
                platform_device_register(&db1100_spi_dev);
        } else if (board == BCSR_WHOAMI_DB1000) {
                c0 = AU1000_GPIO2_INT;
 
        .pixclk_falling_edge = 1,
 };
 
-struct spi_gpio_platform_data spigpio_platform_data = {
-       .sck = JZ_GPIO_PORTC(23),
-       .mosi = JZ_GPIO_PORTC(22),
-       .miso = -1,
+struct spi_gpio_platform_data qi_lb60_spigpio_platform_data = {
        .num_chipselect = 1,
 };
 
-static struct platform_device spigpio_device = {
+static struct platform_device qi_lb60_spigpio_device = {
        .name = "spi_gpio",
        .id   = 1,
        .dev = {
-               .platform_data = &spigpio_platform_data,
+               .platform_data = &qi_lb60_spigpio_platform_data,
+       },
+};
+
+static struct gpiod_lookup_table qi_lb60_spigpio_gpio_table = {
+       .dev_id         = "spi_gpio",
+       .table          = {
+               GPIO_LOOKUP("GPIOC", 23,
+                           "sck", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOC", 22,
+                           "mosi", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOC", 21,
+                           "cs", GPIO_ACTIVE_HIGH),
+               { },
        },
 };
 
 static struct spi_board_info qi_lb60_spi_board_info[] = {
        {
                .modalias = "ili8960",
-               .controller_data = (void *)JZ_GPIO_PORTC(21),
                .chip_select = 0,
                .bus_num = 1,
                .max_speed_hz = 30 * 1000,
        &jz4740_mmc_device,
        &jz4740_nand_device,
        &qi_lb60_keypad,
-       &spigpio_device,
+       &qi_lb60_spigpio_device,
        &jz4740_framebuffer_device,
        &jz4740_pcm_device,
        &jz4740_i2s_device,
 
        gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
        gpiod_add_lookup_table(&qi_lb60_nand_gpio_table);
+       gpiod_add_lookup_table(&qi_lb60_spigpio_gpio_table);
 
        spi_register_board_info(qi_lb60_spi_board_info,
                                ARRAY_SIZE(qi_lb60_spi_board_info));
 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
+ *
+ * FIXME: this driver is used on a device-tree probed platform: it
+ * should be defined as a bit-banged SPI device and probed from the device
+ * tree and not like this with static grabbing of a few numbered GPIO
+ * lines at random.
+ *
+ * Add proper SPI and EEPROM in arch/powerpc/boot/dts/digsy_mtc.dts
+ * and delete this driver.
  */
 
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 };
 
 static struct spi_gpio_platform_data eeprom_spi_gpio_data = {
-       .sck            = GPIO_EEPROM_CLK,
-       .mosi           = GPIO_EEPROM_DI,
-       .miso           = GPIO_EEPROM_DO,
        .num_chipselect = 1,
 };
 
        },
 };
 
+static struct gpiod_lookup_table eeprom_spi_gpiod_table = {
+       .dev_id         = "spi_gpio",
+       .table          = {
+               GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CLK,
+                           "sck", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_DI,
+                           "mosi", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_DO,
+                           "miso", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CS,
+                           "cs", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = {
        {
                .modalias               = "93xx46",
                .bus_num                = EE_SPI_BUS_NUM,
                .chip_select            = 0,
                .mode                   = SPI_MODE_0,
-               .controller_data        = (void *)GPIO_EEPROM_CS,
                .platform_data          = &digsy_mtc_eeprom_data,
        },
 };
                pr_err("can't request gpio %d\n", GPIO_EEPROM_OE);
                return ret;
        }
+       gpiod_add_lookup_table(&eeprom_spi_gpiod_table);
        spi_register_board_info(digsy_mtc_eeprom_info,
                                ARRAY_SIZE(digsy_mtc_eeprom_info));
        return platform_device_register(&digsy_mtc_eeprom);
 
  * SPI master driver using generic bitbanged GPIO
  *
  * Copyright (C) 2006,2008 David Brownell
+ * Copyright (C) 2017 Linus Walleij
  *
  * 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
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
        struct spi_bitbang              bitbang;
        struct spi_gpio_platform_data   pdata;
        struct platform_device          *pdev;
-       unsigned long                   cs_gpios[0];
+       struct gpio_desc                *sck;
+       struct gpio_desc                *miso;
+       struct gpio_desc                *mosi;
+       struct gpio_desc                **cs_gpios;
+       bool                            has_cs;
 };
 
 /*----------------------------------------------------------------------*/
 
 #define GENERIC_BITBANG        /* vs tight inlines */
 
-/* all functions referencing these symbols must define pdata */
-#define SPI_MISO_GPIO  ((pdata)->miso)
-#define SPI_MOSI_GPIO  ((pdata)->mosi)
-#define SPI_SCK_GPIO   ((pdata)->sck)
-
-#define SPI_N_CHIPSEL  ((pdata)->num_chipselect)
-
 #endif
 
 /*----------------------------------------------------------------------*/
        return &spi_to_spi_gpio(spi)->pdata;
 }
 
-/* this is #defined to avoid unused-variable warnings when inlining */
-#define pdata          spi_to_pdata(spi)
-
+/* These helpers are in turn called by the bitbang inlines */
 static inline void setsck(const struct spi_device *spi, int is_on)
 {
-       gpio_set_value_cansleep(SPI_SCK_GPIO, is_on);
+       struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+
+       gpiod_set_value_cansleep(spi_gpio->sck, is_on);
 }
 
 static inline void setmosi(const struct spi_device *spi, int is_on)
 {
-       gpio_set_value_cansleep(SPI_MOSI_GPIO, is_on);
+       struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+
+       gpiod_set_value_cansleep(spi_gpio->mosi, is_on);
 }
 
 static inline int getmiso(const struct spi_device *spi)
 {
-       return !!gpio_get_value_cansleep(SPI_MISO_GPIO);
-}
+       struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
 
-#undef pdata
+       return !!gpiod_get_value_cansleep(spi_gpio->miso);
+}
 
 /*
  * NOTE:  this clocks "as fast as we can".  It "should" be a function of the
 static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
 {
        struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
-       unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];
 
-       /* set initial clock polarity */
+       /* set initial clock line level */
        if (is_active)
-               setsck(spi, spi->mode & SPI_CPOL);
+               gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL);
+
+       /* Drive chip select line, if we have one */
+       if (spi_gpio->has_cs) {
+               struct gpio_desc *cs = spi_gpio->cs_gpios[spi->chip_select];
 
-       if (cs != SPI_GPIO_NO_CHIPSELECT) {
-               /* SPI is normally active-low */
-               gpio_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+               /* SPI chip selects are normally active-low */
+               gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
        }
 }
 
 static int spi_gpio_setup(struct spi_device *spi)
 {
-       unsigned long           cs;
+       struct gpio_desc        *cs;
        int                     status = 0;
        struct spi_gpio         *spi_gpio = spi_to_spi_gpio(spi);
-       struct device_node      *np = spi->master->dev.of_node;
-
-       if (np) {
-               /*
-                * In DT environments, the CS GPIOs have already been
-                * initialized from the "cs-gpios" property of the node.
-                */
-               cs = spi_gpio->cs_gpios[spi->chip_select];
-       } else {
-               /*
-                * ... otherwise, take it from spi->controller_data
-                */
-               cs = (uintptr_t) spi->controller_data;
-       }
 
-       if (!spi->controller_state) {
-               if (cs != SPI_GPIO_NO_CHIPSELECT) {
-                       status = gpio_request(cs, dev_name(&spi->dev));
-                       if (status)
-                               return status;
-                       status = gpio_direction_output(cs,
-                                       !(spi->mode & SPI_CS_HIGH));
-               }
-       }
-       if (!status) {
-               /* in case it was initialized from static board data */
-               spi_gpio->cs_gpios[spi->chip_select] = cs;
+       /*
+        * The CS GPIOs have already been
+        * initialized from the descriptor lookup.
+        */
+       cs = spi_gpio->cs_gpios[spi->chip_select];
+       if (!spi->controller_state && cs)
+               status = gpiod_direction_output(cs,
+                                               !(spi->mode & SPI_CS_HIGH));
+
+       if (!status)
                status = spi_bitbang_setup(spi);
-       }
 
-       if (status) {
-               if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT)
-                       gpio_free(cs);
-       }
        return status;
 }
 
 static void spi_gpio_cleanup(struct spi_device *spi)
 {
-       struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
-       unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];
-
-       if (cs != SPI_GPIO_NO_CHIPSELECT)
-               gpio_free(cs);
        spi_bitbang_cleanup(spi);
 }
 
-static int spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
-{
-       int value;
-
-       value = gpio_request(pin, label);
-       if (value == 0) {
-               if (is_in)
-                       value = gpio_direction_input(pin);
-               else
-                       value = gpio_direction_output(pin, 0);
-       }
-       return value;
-}
-
-static int spi_gpio_request(struct spi_gpio_platform_data *pdata,
-                           const char *label, u16 *res_flags)
+/*
+ * It can be convenient to use this driver with pins that have alternate
+ * functions associated with a "native" SPI controller if a driver for that
+ * controller is not available, or is missing important functionality.
+ *
+ * On platforms which can do so, configure MISO with a weak pullup unless
+ * there's an external pullup on that signal.  That saves power by avoiding
+ * floating signals.  (A weak pulldown would save power too, but many
+ * drivers expect to see all-ones data as the no slave "response".)
+ */
+static int spi_gpio_request(struct device *dev,
+                           struct spi_gpio *spi_gpio,
+                           unsigned int num_chipselects,
+                           u16 *mflags)
 {
-       int value;
-
-       /* NOTE:  SPI_*_GPIO symbols may reference "pdata" */
+       int i;
 
-       if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) {
-               value = spi_gpio_alloc(SPI_MOSI_GPIO, label, false);
-               if (value)
-                       goto done;
-       } else {
+       spi_gpio->mosi = devm_gpiod_get_optional(dev, "mosi", GPIOD_OUT_LOW);
+       if (IS_ERR(spi_gpio->mosi))
+               return PTR_ERR(spi_gpio->mosi);
+       if (!spi_gpio->mosi)
                /* HW configuration without MOSI pin */
-               *res_flags |= SPI_MASTER_NO_TX;
-       }
+               *mflags |= SPI_MASTER_NO_TX;
 
-       if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) {
-               value = spi_gpio_alloc(SPI_MISO_GPIO, label, true);
-               if (value)
-                       goto free_mosi;
-       } else {
+       spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN);
+       if (IS_ERR(spi_gpio->miso))
+               return PTR_ERR(spi_gpio->miso);
+       if (!spi_gpio->miso)
                /* HW configuration without MISO pin */
-               *res_flags |= SPI_MASTER_NO_RX;
-       }
+               *mflags |= SPI_MASTER_NO_RX;
 
-       value = spi_gpio_alloc(SPI_SCK_GPIO, label, false);
-       if (value)
-               goto free_miso;
+       spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
+       if (IS_ERR(spi_gpio->mosi))
+               return PTR_ERR(spi_gpio->mosi);
 
-       goto done;
+       for (i = 0; i < num_chipselects; i++) {
+               spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs",
+                                                            i, GPIOD_OUT_HIGH);
+               if (IS_ERR(spi_gpio->cs_gpios[i]))
+                       return PTR_ERR(spi_gpio->cs_gpios[i]);
+       }
 
-free_miso:
-       if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
-               gpio_free(SPI_MISO_GPIO);
-free_mosi:
-       if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
-               gpio_free(SPI_MOSI_GPIO);
-done:
-       return value;
+       return 0;
 }
 
 #ifdef CONFIG_OF
        if (!pdata)
                return -ENOMEM;
 
-       ret = of_get_named_gpio(np, "gpio-sck", 0);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "gpio-sck property not found\n");
-               goto error_free;
-       }
-       pdata->sck = ret;
-
-       ret = of_get_named_gpio(np, "gpio-miso", 0);
-       if (ret < 0) {
-               dev_info(&pdev->dev, "gpio-miso property not found, switching to no-rx mode\n");
-               pdata->miso = SPI_GPIO_NO_MISO;
-       } else
-               pdata->miso = ret;
-
-       ret = of_get_named_gpio(np, "gpio-mosi", 0);
-       if (ret < 0) {
-               dev_info(&pdev->dev, "gpio-mosi property not found, switching to no-tx mode\n");
-               pdata->mosi = SPI_GPIO_NO_MOSI;
-       } else
-               pdata->mosi = ret;
 
        ret = of_property_read_u32(np, "num-chipselects", &tmp);
        if (ret < 0) {
        struct spi_gpio_platform_data   *pdata;
        u16 master_flags = 0;
        bool use_of = 0;
-       int num_devices;
 
        status = spi_gpio_probe_dt(pdev);
        if (status < 0)
                return -ENODEV;
 #endif
 
-       if (use_of && !SPI_N_CHIPSEL)
-               num_devices = 1;
-       else
-               num_devices = SPI_N_CHIPSEL;
-
-       status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);
-       if (status < 0)
-               return status;
+       master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio));
+       if (!master)
+               return -ENOMEM;
 
-       master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) +
-                                       (sizeof(unsigned long) * num_devices));
-       if (!master) {
-               status = -ENOMEM;
-               goto gpio_free;
-       }
        spi_gpio = spi_master_get_devdata(master);
+
+       spi_gpio->cs_gpios = devm_kzalloc(&pdev->dev,
+                               pdata->num_chipselect * sizeof(*spi_gpio->cs_gpios),
+                               GFP_KERNEL);
+       if (!spi_gpio->cs_gpios)
+               return -ENOMEM;
+
        platform_set_drvdata(pdev, spi_gpio);
 
+       /* Determine if we have chip selects connected */
+       spi_gpio->has_cs = !!pdata->num_chipselect;
+
        spi_gpio->pdev = pdev;
        if (pdata)
                spi_gpio->pdata = *pdata;
 
+       status = spi_gpio_request(&pdev->dev, spi_gpio,
+                                 pdata->num_chipselect, &master_flags);
+       if (status)
+               return status;
+
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
        master->flags = master_flags;
        master->bus_num = pdev->id;
-       master->num_chipselect = num_devices;
+       /* The master needs to think there is a chipselect even if not connected */
+       master->num_chipselect = spi_gpio->has_cs ? pdata->num_chipselect : 1;
        master->setup = spi_gpio_setup;
        master->cleanup = spi_gpio_cleanup;
 #ifdef CONFIG_OF
        master->dev.of_node = pdev->dev.of_node;
-
-       if (use_of) {
-               int i;
-               struct device_node *np = pdev->dev.of_node;
-
-               /*
-                * In DT environments, take the CS GPIO from the "cs-gpios"
-                * property of the node.
-                */
-
-               if (!SPI_N_CHIPSEL)
-                       spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT;
-               else
-                       for (i = 0; i < SPI_N_CHIPSEL; i++) {
-                               status = of_get_named_gpio(np, "cs-gpios", i);
-                               if (status < 0) {
-                                       dev_err(&pdev->dev,
-                                               "invalid cs-gpios property\n");
-                                       goto gpio_free;
-                               }
-                               spi_gpio->cs_gpios[i] = status;
-                       }
-       }
 #endif
 
        spi_gpio->bitbang.master = master;
        spi_gpio->bitbang.flags = SPI_CS_HIGH;
 
        status = spi_bitbang_start(&spi_gpio->bitbang);
-       if (status < 0) {
-gpio_free:
-               if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
-                       gpio_free(SPI_MISO_GPIO);
-               if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
-                       gpio_free(SPI_MOSI_GPIO);
-               gpio_free(SPI_SCK_GPIO);
+       if (status)
                spi_master_put(master);
-       }
 
        return status;
 }
        /* stop() unregisters child devices too */
        spi_bitbang_stop(&spi_gpio->bitbang);
 
-       if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
-               gpio_free(SPI_MISO_GPIO);
-       if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
-               gpio_free(SPI_MOSI_GPIO);
-       gpio_free(SPI_SCK_GPIO);
        spi_master_put(spi_gpio->bitbang.master);
 
        return 0;
 
  *   - id the same as the SPI bus number it implements
  *   - dev.platform data pointing to a struct spi_gpio_platform_data
  *
- * Or, see the driver code for information about speedups that are
- * possible on platforms that support inlined access for GPIOs (no
- * spi_gpio_platform_data is used).
- *
- * Use spi_board_info with these busses in the usual way, being sure
- * that the controller_data being the GPIO used for each device's
- * chipselect:
- *
- *     static struct spi_board_info ... [] = {
- *     ...
- *             // this slave uses GPIO 42 for its chipselect
- *             .controller_data = (void *) 42,
- *     ...
- *             // this one uses GPIO 86 for its chipselect
- *             .controller_data = (void *) 86,
- *     ...
- *     };
- *
- * If chipselect is not used (there's only one device on the bus), assign
- * SPI_GPIO_NO_CHIPSELECT to the controller_data:
- *             .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT;
- *
- * If the MISO or MOSI pin is not available then it should be set to
- * SPI_GPIO_NO_MISO or SPI_GPIO_NO_MOSI.
+ * Use spi_board_info with these busses in the usual way.
  *
  * If the bitbanged bus is later switched to a "native" controller,
  * that platform_device and controller_data should be removed.
  */
 
-#define SPI_GPIO_NO_CHIPSELECT         ((unsigned long)-1l)
-#define SPI_GPIO_NO_MISO               ((unsigned long)-1l)
-#define SPI_GPIO_NO_MOSI               ((unsigned long)-1l)
-
 /**
  * struct spi_gpio_platform_data - parameter for bitbanged SPI master
- * @sck: number of the GPIO used for clock output
- * @mosi: number of the GPIO used for Master Output, Slave In (MOSI) data
- * @miso: number of the GPIO used for Master Input, Slave Output (MISO) data
  * @num_chipselect: how many slaves to allow
- *
- * All GPIO signals used with the SPI bus managed through this driver
- * (chipselects, MOSI, MISO, SCK) must be configured as GPIOs, instead
- * of some alternate function.
- *
- * It can be convenient to use this driver with pins that have alternate
- * functions associated with a "native" SPI controller if a driver for that
- * controller is not available, or is missing important functionality.
- *
- * On platforms which can do so, configure MISO with a weak pullup unless
- * there's an external pullup on that signal.  That saves power by avoiding
- * floating signals.  (A weak pulldown would save power too, but many
- * drivers expect to see all-ones data as the no slave "response".)
  */
 struct spi_gpio_platform_data {
-       unsigned        sck;
-       unsigned long   mosi;
-       unsigned long   miso;
-
        u16             num_chipselect;
 };