Merge branch 'printk-cleanups'
[cascardo/linux.git] / drivers / spi / spi-pxa2xx.c
index 6a0eb32..dd7b5b4 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/spi/spi.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
@@ -62,6 +63,13 @@ MODULE_ALIAS("platform:pxa2xx-spi");
                                | QUARK_X1000_SSCR1_TFT         \
                                | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
 
+#define CE4100_SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \
+                               | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
+                               | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \
+                               | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \
+                               | CE4100_SSCR1_RFT | CE4100_SSCR1_TFT | SSCR1_MWDS \
+                               | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
+
 #define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE  BIT(24)
 #define LPSS_CS_CONTROL_SW_MODE                        BIT(0)
 #define LPSS_CS_CONTROL_CS_HIGH                        BIT(1)
@@ -175,6 +183,8 @@ static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data)
        switch (drv_data->ssp_type) {
        case QUARK_X1000_SSP:
                return QUARK_X1000_SSCR1_CHANGE_MASK;
+       case CE4100_SSP:
+               return CE4100_SSCR1_CHANGE_MASK;
        default:
                return SSCR1_CHANGE_MASK;
        }
@@ -186,6 +196,8 @@ pxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data)
        switch (drv_data->ssp_type) {
        case QUARK_X1000_SSP:
                return RX_THRESH_QUARK_X1000_DFLT;
+       case CE4100_SSP:
+               return RX_THRESH_CE4100_DFLT;
        default:
                return RX_THRESH_DFLT;
        }
@@ -199,6 +211,9 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
        case QUARK_X1000_SSP:
                mask = QUARK_X1000_SSSR_TFL_MASK;
                break;
+       case CE4100_SSP:
+               mask = CE4100_SSSR_TFL_MASK;
+               break;
        default:
                mask = SSSR_TFL_MASK;
                break;
@@ -216,6 +231,9 @@ static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data,
        case QUARK_X1000_SSP:
                mask = QUARK_X1000_SSCR1_RFT;
                break;
+       case CE4100_SSP:
+               mask = CE4100_SSCR1_RFT;
+               break;
        default:
                mask = SSCR1_RFT;
                break;
@@ -230,6 +248,9 @@ static void pxa2xx_spi_set_rx_thre(const struct driver_data *drv_data,
        case QUARK_X1000_SSP:
                *sccr1_reg |= QUARK_X1000_SSCR1_RxTresh(threshold);
                break;
+       case CE4100_SSP:
+               *sccr1_reg |= CE4100_SSCR1_RxTresh(threshold);
+               break;
        default:
                *sccr1_reg |= SSCR1_RxTresh(threshold);
                break;
@@ -590,6 +611,9 @@ static void reset_sccr1(struct driver_data *drv_data)
        case QUARK_X1000_SSP:
                sccr1_reg &= ~QUARK_X1000_SSCR1_RFT;
                break;
+       case CE4100_SSP:
+               sccr1_reg &= ~CE4100_SSCR1_RFT;
+               break;
        default:
                sccr1_reg &= ~SSCR1_RFT;
                break;
@@ -1171,9 +1195,26 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
 static int setup_cs(struct spi_device *spi, struct chip_data *chip,
                    struct pxa2xx_spi_chip *chip_info)
 {
+       struct driver_data *drv_data = spi_master_get_devdata(spi->master);
        int err = 0;
 
-       if (chip == NULL || chip_info == NULL)
+       if (chip == NULL)
+               return 0;
+
+       if (drv_data->cs_gpiods) {
+               struct gpio_desc *gpiod;
+
+               gpiod = drv_data->cs_gpiods[spi->chip_select];
+               if (gpiod) {
+                       chip->gpio_cs = desc_to_gpio(gpiod);
+                       chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
+                       gpiod_set_value(gpiod, chip->gpio_cs_inverted);
+               }
+
+               return 0;
+       }
+
+       if (chip_info == NULL)
                return 0;
 
        /* NOTE: setup() can be called multiple times, possibly with
@@ -1220,6 +1261,11 @@ static int setup(struct spi_device *spi)
                tx_hi_thres = 0;
                rx_thres = RX_THRESH_QUARK_X1000_DFLT;
                break;
+       case CE4100_SSP:
+               tx_thres = TX_THRESH_CE4100_DFLT;
+               tx_hi_thres = 0;
+               rx_thres = RX_THRESH_CE4100_DFLT;
+               break;
        case LPSS_LPT_SSP:
        case LPSS_BYT_SSP:
        case LPSS_BSW_SSP:
@@ -1304,6 +1350,10 @@ static int setup(struct spi_device *spi)
                                   | (QUARK_X1000_SSCR1_TxTresh(tx_thres)
                                   & QUARK_X1000_SSCR1_TFT);
                break;
+       case CE4100_SSP:
+               chip->threshold = (CE4100_SSCR1_RxTresh(rx_thres) & CE4100_SSCR1_RFT) |
+                       (CE4100_SSCR1_TxTresh(tx_thres) & CE4100_SSCR1_TFT);
+               break;
        default:
                chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
                        (SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
@@ -1347,7 +1397,8 @@ static void cleanup(struct spi_device *spi)
        if (!chip)
                return;
 
-       if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs))
+       if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods &&
+           gpio_is_valid(chip->gpio_cs))
                gpio_free(chip->gpio_cs);
 
        kfree(chip);
@@ -1525,7 +1576,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        struct driver_data *drv_data;
        struct ssp_device *ssp;
        const struct lpss_config *config;
-       int status;
+       int status, count;
        u32 tmp;
 
        platform_info = dev_get_platdata(dev);
@@ -1625,15 +1676,20 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        pxa2xx_spi_write(drv_data, SSCR0, 0);
        switch (drv_data->ssp_type) {
        case QUARK_X1000_SSP:
-               tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT)
-                     QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT);
+               tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) |
+                     QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT);
                pxa2xx_spi_write(drv_data, SSCR1, tmp);
 
                /* using the Motorola SPI protocol and use 8 bit frame */
-               pxa2xx_spi_write(drv_data, SSCR0,
-                                QUARK_X1000_SSCR0_Motorola
-                                | QUARK_X1000_SSCR0_DataSize(8));
+               tmp = QUARK_X1000_SSCR0_Motorola | QUARK_X1000_SSCR0_DataSize(8);
+               pxa2xx_spi_write(drv_data, SSCR0, tmp);
                break;
+       case CE4100_SSP:
+               tmp = CE4100_SSCR1_RxTresh(RX_THRESH_CE4100_DFLT) |
+                     CE4100_SSCR1_TxTresh(TX_THRESH_CE4100_DFLT);
+               pxa2xx_spi_write(drv_data, SSCR1, tmp);
+               tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8);
+               pxa2xx_spi_write(drv_data, SSCR0, tmp);
        default:
                tmp = SSCR1_RxTresh(RX_THRESH_DFLT) |
                      SSCR1_TxTresh(TX_THRESH_DFLT);
@@ -1664,6 +1720,39 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        }
        master->num_chipselect = platform_info->num_chipselect;
 
+       count = gpiod_count(&pdev->dev, "cs");
+       if (count > 0) {
+               int i;
+
+               master->num_chipselect = max_t(int, count,
+                       master->num_chipselect);
+
+               drv_data->cs_gpiods = devm_kcalloc(&pdev->dev,
+                       master->num_chipselect, sizeof(struct gpio_desc *),
+                       GFP_KERNEL);
+               if (!drv_data->cs_gpiods) {
+                       status = -ENOMEM;
+                       goto out_error_clock_enabled;
+               }
+
+               for (i = 0; i < master->num_chipselect; i++) {
+                       struct gpio_desc *gpiod;
+
+                       gpiod = devm_gpiod_get_index(dev, "cs", i,
+                                                    GPIOD_OUT_HIGH);
+                       if (IS_ERR(gpiod)) {
+                               /* Means use native chip select */
+                               if (PTR_ERR(gpiod) == -ENOENT)
+                                       continue;
+
+                               status = (int)PTR_ERR(gpiod);
+                               goto out_error_clock_enabled;
+                       } else {
+                               drv_data->cs_gpiods[i] = gpiod;
+                       }
+               }
+       }
+
        tasklet_init(&drv_data->pump_transfers, pump_transfers,
                     (unsigned long)drv_data);