gfs2: Simplify the seq file code for "sbstats"
[deliverable/linux.git] / drivers / spi / spi-pxa2xx.c
index 6f72ad01e0410257a42bc8739f8962abfbaf3b5e..7293d6d875c5c692184d1c45aea151f063bb6cd0 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/spi/spi.h>
 #include <linux/pm_runtime.h>
 #include <linux/acpi.h>
 
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-
 #include "spi-pxa2xx.h"
 
 MODULE_AUTHOR("Stephen Street");
@@ -63,69 +60,60 @@ MODULE_ALIAS("platform:pxa2xx-spi");
                                | QUARK_X1000_SSCR1_TFT         \
                                | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
 
-#define LPSS_RX_THRESH_DFLT    64
-#define LPSS_TX_LOTHRESH_DFLT  160
-#define LPSS_TX_HITHRESH_DFLT  224
+#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
+#define SPI_CS_CONTROL_SW_MODE BIT(0)
+#define SPI_CS_CONTROL_CS_HIGH BIT(1)
 
-struct quark_spi_rate {
-       u32 bitrate;
-       u32 dds_clk_rate;
-       u32 clk_div;
+struct lpss_config {
+       /* LPSS offset from drv_data->ioaddr */
+       unsigned offset;
+       /* Register offsets from drv_data->lpss_base or -1 */
+       int reg_general;
+       int reg_ssp;
+       int reg_cs_ctrl;
+       /* FIFO thresholds */
+       u32 rx_threshold;
+       u32 tx_threshold_lo;
+       u32 tx_threshold_hi;
 };
 
-/*
- * 'rate', 'dds', 'clk_div' lookup table, which is defined in
- * the Quark SPI datasheet.
- */
-static const struct quark_spi_rate quark_spi_rate_table[] = {
-/*     bitrate,        dds_clk_rate,   clk_div */
-       {50000000,      0x800000,       0},
-       {40000000,      0x666666,       0},
-       {25000000,      0x400000,       0},
-       {20000000,      0x666666,       1},
-       {16667000,      0x800000,       2},
-       {13333000,      0x666666,       2},
-       {12500000,      0x200000,       0},
-       {10000000,      0x800000,       4},
-       {8000000,       0x666666,       4},
-       {6250000,       0x400000,       3},
-       {5000000,       0x400000,       4},
-       {4000000,       0x666666,       9},
-       {3125000,       0x80000,        0},
-       {2500000,       0x400000,       9},
-       {2000000,       0x666666,       19},
-       {1563000,       0x40000,        0},
-       {1250000,       0x200000,       9},
-       {1000000,       0x400000,       24},
-       {800000,        0x666666,       49},
-       {781250,        0x20000,        0},
-       {625000,        0x200000,       19},
-       {500000,        0x400000,       49},
-       {400000,        0x666666,       99},
-       {390625,        0x10000,        0},
-       {250000,        0x400000,       99},
-       {200000,        0x666666,       199},
-       {195313,        0x8000,         0},
-       {125000,        0x100000,       49},
-       {100000,        0x200000,       124},
-       {50000,         0x100000,       124},
-       {25000,         0x80000,        124},
-       {10016,         0x20000,        77},
-       {5040,          0x20000,        154},
-       {1002,          0x8000,         194},
+/* Keep these sorted with enum pxa_ssp_type */
+static const struct lpss_config lpss_platforms[] = {
+       {       /* LPSS_LPT_SSP */
+               .offset = 0x800,
+               .reg_general = 0x08,
+               .reg_ssp = 0x0c,
+               .reg_cs_ctrl = 0x18,
+               .rx_threshold = 64,
+               .tx_threshold_lo = 160,
+               .tx_threshold_hi = 224,
+       },
+       {       /* LPSS_BYT_SSP */
+               .offset = 0x400,
+               .reg_general = 0x08,
+               .reg_ssp = 0x0c,
+               .reg_cs_ctrl = 0x18,
+               .rx_threshold = 64,
+               .tx_threshold_lo = 160,
+               .tx_threshold_hi = 224,
+       },
 };
 
-/* Offset from drv_data->lpss_base */
-#define GENERAL_REG            0x08
-#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
-#define SSP_REG                        0x0c
-#define SPI_CS_CONTROL         0x18
-#define SPI_CS_CONTROL_SW_MODE BIT(0)
-#define SPI_CS_CONTROL_CS_HIGH BIT(1)
+static inline const struct lpss_config
+*lpss_get_config(const struct driver_data *drv_data)
+{
+       return &lpss_platforms[drv_data->ssp_type - LPSS_LPT_SSP];
+}
 
 static bool is_lpss_ssp(const struct driver_data *drv_data)
 {
-       return drv_data->ssp_type == LPSS_SSP;
+       switch (drv_data->ssp_type) {
+       case LPSS_LPT_SSP:
+       case LPSS_BYT_SSP:
+               return true;
+       default:
+               return false;
+       }
 }
 
 static bool is_quark_x1000_ssp(const struct driver_data *drv_data)
@@ -243,63 +231,43 @@ static void __lpss_ssp_write_priv(struct driver_data *drv_data,
  */
 static void lpss_ssp_setup(struct driver_data *drv_data)
 {
-       unsigned offset = 0x400;
-       u32 value, orig;
-
-       /*
-        * Perform auto-detection of the LPSS SSP private registers. They
-        * can be either at 1k or 2k offset from the base address.
-        */
-       orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
-
-       /* Test SPI_CS_CONTROL_SW_MODE bit enabling */
-       value = orig | SPI_CS_CONTROL_SW_MODE;
-       writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
-       value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
-       if (value != (orig | SPI_CS_CONTROL_SW_MODE)) {
-               offset = 0x800;
-               goto detection_done;
-       }
-
-       orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
-
-       /* Test SPI_CS_CONTROL_SW_MODE bit disabling */
-       value = orig & ~SPI_CS_CONTROL_SW_MODE;
-       writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
-       value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
-       if (value != (orig & ~SPI_CS_CONTROL_SW_MODE)) {
-               offset = 0x800;
-               goto detection_done;
-       }
+       const struct lpss_config *config;
+       u32 value;
 
-detection_done:
-       /* Now set the LPSS base */
-       drv_data->lpss_base = drv_data->ioaddr + offset;
+       config = lpss_get_config(drv_data);
+       drv_data->lpss_base = drv_data->ioaddr + config->offset;
 
        /* Enable software chip select control */
        value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH;
-       __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
+       __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
 
        /* Enable multiblock DMA transfers */
        if (drv_data->master_info->enable_dma) {
-               __lpss_ssp_write_priv(drv_data, SSP_REG, 1);
-
-               value = __lpss_ssp_read_priv(drv_data, GENERAL_REG);
-               value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
-               __lpss_ssp_write_priv(drv_data, GENERAL_REG, value);
+               __lpss_ssp_write_priv(drv_data, config->reg_ssp, 1);
+
+               if (config->reg_general >= 0) {
+                       value = __lpss_ssp_read_priv(drv_data,
+                                                    config->reg_general);
+                       value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
+                       __lpss_ssp_write_priv(drv_data,
+                                             config->reg_general, value);
+               }
        }
 }
 
 static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
 {
+       const struct lpss_config *config;
        u32 value;
 
-       value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL);
+       config = lpss_get_config(drv_data);
+
+       value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
        if (enable)
                value &= ~SPI_CS_CONTROL_CS_HIGH;
        else
                value |= SPI_CS_CONTROL_CS_HIGH;
-       __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
+       __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
 }
 
 static void cs_assert(struct driver_data *drv_data)
@@ -701,25 +669,124 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
 }
 
 /*
- * The Quark SPI data sheet gives a table, and for the given 'rate',
- * the 'dds' and 'clk_div' can be found in the table.
+ * The Quark SPI has an additional 24 bit register (DDS_CLK_RATE) to multiply
+ * input frequency by fractions of 2^24. It also has a divider by 5.
+ *
+ * There are formulas to get baud rate value for given input frequency and
+ * divider parameters, such as DDS_CLK_RATE and SCR:
+ *
+ * Fsys = 200MHz
+ *
+ * Fssp = Fsys * DDS_CLK_RATE / 2^24                   (1)
+ * Baud rate = Fsclk = Fssp / (2 * (SCR + 1))          (2)
+ *
+ * DDS_CLK_RATE either 2^n or 2^n / 5.
+ * SCR is in range 0 .. 255
+ *
+ * Divisor = 5^i * 2^j * 2 * k
+ *       i = [0, 1]      i = 1 iff j = 0 or j > 3
+ *       j = [0, 23]     j = 0 iff i = 1
+ *       k = [1, 256]
+ * Special case: j = 0, i = 1: Divisor = 2 / 5
+ *
+ * Accordingly to the specification the recommended values for DDS_CLK_RATE
+ * are:
+ *     Case 1:         2^n, n = [0, 23]
+ *     Case 2:         2^24 * 2 / 5 (0x666666)
+ *     Case 3:         less than or equal to 2^24 / 5 / 16 (0x33333)
+ *
+ * In all cases the lowest possible value is better.
+ *
+ * The function calculates parameters for all cases and chooses the one closest
+ * to the asked baud rate.
  */
-static u32 quark_x1000_set_clk_regvals(u32 rate, u32 *dds, u32 *clk_div)
+static unsigned int quark_x1000_get_clk_div(int rate, u32 *dds)
 {
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(quark_spi_rate_table); i++) {
-               if (rate >= quark_spi_rate_table[i].bitrate) {
-                       *dds = quark_spi_rate_table[i].dds_clk_rate;
-                       *clk_div = quark_spi_rate_table[i].clk_div;
-                       return quark_spi_rate_table[i].bitrate;
+       unsigned long xtal = 200000000;
+       unsigned long fref = xtal / 2;          /* mandatory division by 2,
+                                                  see (2) */
+                                               /* case 3 */
+       unsigned long fref1 = fref / 2;         /* case 1 */
+       unsigned long fref2 = fref * 2 / 5;     /* case 2 */
+       unsigned long scale;
+       unsigned long q, q1, q2;
+       long r, r1, r2;
+       u32 mul;
+
+       /* Case 1 */
+
+       /* Set initial value for DDS_CLK_RATE */
+       mul = (1 << 24) >> 1;
+
+       /* Calculate initial quot */
+       q1 = DIV_ROUND_CLOSEST(fref1, rate);
+
+       /* Scale q1 if it's too big */
+       if (q1 > 256) {
+               /* Scale q1 to range [1, 512] */
+               scale = fls_long(q1 - 1);
+               if (scale > 9) {
+                       q1 >>= scale - 9;
+                       mul >>= scale - 9;
                }
+
+               /* Round the result if we have a remainder */
+               q1 += q1 & 1;
        }
 
-       *dds = quark_spi_rate_table[i-1].dds_clk_rate;
-       *clk_div = quark_spi_rate_table[i-1].clk_div;
+       /* Decrease DDS_CLK_RATE as much as we can without loss in precision */
+       scale = __ffs(q1);
+       q1 >>= scale;
+       mul >>= scale;
+
+       /* Get the remainder */
+       r1 = abs(fref1 / (1 << (24 - fls_long(mul))) / q1 - rate);
+
+       /* Case 2 */
 
-       return quark_spi_rate_table[i-1].bitrate;
+       q2 = DIV_ROUND_CLOSEST(fref2, rate);
+       r2 = abs(fref2 / q2 - rate);
+
+       /*
+        * Choose the best between two: less remainder we have the better. We
+        * can't go case 2 if q2 is greater than 256 since SCR register can
+        * hold only values 0 .. 255.
+        */
+       if (r2 >= r1 || q2 > 256) {
+               /* case 1 is better */
+               r = r1;
+               q = q1;
+       } else {
+               /* case 2 is better */
+               r = r2;
+               q = q2;
+               mul = (1 << 24) * 2 / 5;
+       }
+
+       /* Check case 3 only If the divisor is big enough */
+       if (fref / rate >= 80) {
+               u64 fssp;
+               u32 m;
+
+               /* Calculate initial quot */
+               q1 = DIV_ROUND_CLOSEST(fref, rate);
+               m = (1 << 24) / q1;
+
+               /* Get the remainder */
+               fssp = (u64)fref * m;
+               do_div(fssp, 1 << 24);
+               r1 = abs(fssp - rate);
+
+               /* Choose this one if it suits better */
+               if (r1 < r) {
+                       /* case 3 is better */
+                       q = 1;
+                       mul = m;
+               }
+       }
+
+       *dds = mul;
+       return q - 1;
 }
 
 static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
@@ -730,23 +797,25 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
        rate = min_t(int, ssp_clk, rate);
 
        if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
-               return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
+               return (ssp_clk / (2 * rate) - 1) & 0xff;
        else
-               return ((ssp_clk / rate - 1) & 0xfff) << 8;
+               return (ssp_clk / rate - 1) & 0xfff;
 }
 
 static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
                                           struct chip_data *chip, int rate)
 {
-       u32 clk_div;
+       unsigned int clk_div;
 
        switch (drv_data->ssp_type) {
        case QUARK_X1000_SSP:
-               quark_x1000_set_clk_regvals(rate, &chip->dds_rate, &clk_div);
-               return clk_div << 8;
+               clk_div = quark_x1000_get_clk_div(rate, &chip->dds_rate);
+               break;
        default:
-               return ssp_get_clk_div(drv_data, rate);
+               clk_div = ssp_get_clk_div(drv_data, rate);
+               break;
        }
+       return clk_div << 8;
 }
 
 static void pump_transfers(unsigned long data)
@@ -1025,6 +1094,7 @@ static int setup(struct spi_device *spi)
 {
        struct pxa2xx_spi_chip *chip_info = NULL;
        struct chip_data *chip;
+       const struct lpss_config *config;
        struct driver_data *drv_data = spi_master_get_devdata(spi->master);
        unsigned int clk_div;
        uint tx_thres, tx_hi_thres, rx_thres;
@@ -1035,10 +1105,12 @@ static int setup(struct spi_device *spi)
                tx_hi_thres = 0;
                rx_thres = RX_THRESH_QUARK_X1000_DFLT;
                break;
-       case LPSS_SSP:
-               tx_thres = LPSS_TX_LOTHRESH_DFLT;
-               tx_hi_thres = LPSS_TX_HITHRESH_DFLT;
-               rx_thres = LPSS_RX_THRESH_DFLT;
+       case LPSS_LPT_SSP:
+       case LPSS_BYT_SSP:
+               config = lpss_get_config(drv_data);
+               tx_thres = config->tx_threshold_lo;
+               tx_hi_thres = config->tx_threshold_hi;
+               rx_thres = config->rx_threshold;
                break;
        default:
                tx_thres = TX_THRESH_DFLT;
@@ -1192,6 +1264,18 @@ static void cleanup(struct spi_device *spi)
 }
 
 #ifdef CONFIG_ACPI
+
+static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
+       { "INT33C0", LPSS_LPT_SSP },
+       { "INT33C1", LPSS_LPT_SSP },
+       { "INT3430", LPSS_LPT_SSP },
+       { "INT3431", LPSS_LPT_SSP },
+       { "80860F0E", LPSS_BYT_SSP },
+       { "8086228E", LPSS_BYT_SSP },
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
+
 static struct pxa2xx_spi_master *
 pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
 {
@@ -1199,12 +1283,19 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
        struct acpi_device *adev;
        struct ssp_device *ssp;
        struct resource *res;
-       int devid;
+       const struct acpi_device_id *id;
+       int devid, type;
 
        if (!ACPI_HANDLE(&pdev->dev) ||
            acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
                return NULL;
 
+       id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
+       if (id)
+               type = (int)id->driver_data;
+       else
+               return NULL;
+
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return NULL;
@@ -1222,7 +1313,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
 
        ssp->clk = devm_clk_get(&pdev->dev, NULL);
        ssp->irq = platform_get_irq(pdev, 0);
-       ssp->type = LPSS_SSP;
+       ssp->type = type;
        ssp->pdev = pdev;
 
        ssp->port_id = -1;
@@ -1235,16 +1326,6 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
        return pdata;
 }
 
-static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
-       { "INT33C0", 0 },
-       { "INT33C1", 0 },
-       { "INT3430", 0 },
-       { "INT3431", 0 },
-       { "80860F0E", 0 },
-       { "8086228E", 0 },
-       { },
-};
-MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
 #else
 static inline struct pxa2xx_spi_master *
 pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
This page took 0.030339 seconds and 5 git commands to generate.