]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge remote-tracking branches 'spi/topic/omap-100k', 'spi/topic/omap-uwire', 'spi...
authorMark Brown <broonie@kernel.org>
Sat, 11 Apr 2015 22:09:18 +0000 (23:09 +0100)
committerMark Brown <broonie@kernel.org>
Sat, 11 Apr 2015 22:09:18 +0000 (23:09 +0100)
Documentation/spi/spi-summary
drivers/spi/spi-omap-100k.c
drivers/spi/spi-omap-uwire.c
drivers/spi/spi-pl022.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi.c
include/linux/spi/spi.h

index d29734bff28c5beb38bf304b5b5d02903044d691..d1824b399b2d1d79059231a52e2552949d9ba24f 100644 (file)
@@ -342,12 +342,11 @@ SPI protocol drivers somewhat resemble platform device drivers:
                .driver = {
                        .name           = "CHIP",
                        .owner          = THIS_MODULE,
+                       .pm             = &CHIP_pm_ops,
                },
 
                .probe          = CHIP_probe,
                .remove         = CHIP_remove,
-               .suspend        = CHIP_suspend,
-               .resume         = CHIP_resume,
        };
 
 The driver core will automatically attempt to bind this driver to any SPI
index d890d309dff9b553364654ae343f322c65d1c51a..35b332dacb13a1e7d91c868dab37ac8a5abc4dac 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
@@ -294,16 +295,6 @@ static int omap1_spi100k_setup(struct spi_device *spi)
        return ret;
 }
 
-static int omap1_spi100k_prepare_hardware(struct spi_master *master)
-{
-       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
-
-       clk_prepare_enable(spi100k->ick);
-       clk_prepare_enable(spi100k->fck);
-
-       return 0;
-}
-
 static int omap1_spi100k_transfer_one_message(struct spi_master *master,
                                              struct spi_message *m)
 {
@@ -372,16 +363,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
        return status;
 }
 
-static int omap1_spi100k_unprepare_hardware(struct spi_master *master)
-{
-       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
-
-       clk_disable_unprepare(spi100k->ick);
-       clk_disable_unprepare(spi100k->fck);
-
-       return 0;
-}
-
 static int omap1_spi100k_probe(struct platform_device *pdev)
 {
        struct spi_master       *master;
@@ -402,14 +383,12 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
 
        master->setup = omap1_spi100k_setup;
        master->transfer_one_message = omap1_spi100k_transfer_one_message;
-       master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware;
-       master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware;
-       master->cleanup = NULL;
        master->num_chipselect = 2;
        master->mode_bits = MODEBITS;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16);
        master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ;
+       master->auto_runtime_pm = true;
 
        spi100k = spi_master_get_devdata(master);
 
@@ -434,22 +413,96 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
                goto err;
        }
 
+       status = clk_prepare_enable(spi100k->ick);
+       if (status != 0) {
+               dev_err(&pdev->dev, "failed to enable ick: %d\n", status);
+               goto err;
+       }
+
+       status = clk_prepare_enable(spi100k->fck);
+       if (status != 0) {
+               dev_err(&pdev->dev, "failed to enable fck: %d\n", status);
+               goto err_ick;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+
        status = devm_spi_register_master(&pdev->dev, master);
        if (status < 0)
-               goto err;
+               goto err_fck;
 
        return status;
 
+err_fck:
+       clk_disable_unprepare(spi100k->fck);
+err_ick:
+       clk_disable_unprepare(spi100k->ick);
 err:
        spi_master_put(master);
        return status;
 }
 
+static int omap1_spi100k_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+       pm_runtime_disable(&pdev->dev);
+
+       clk_disable_unprepare(spi100k->fck);
+       clk_disable_unprepare(spi100k->ick);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap1_spi100k_runtime_suspend(struct device *dev)
+{
+       struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+       clk_disable_unprepare(spi100k->ick);
+       clk_disable_unprepare(spi100k->fck);
+
+       return 0;
+}
+
+static int omap1_spi100k_runtime_resume(struct device *dev)
+{
+       struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+       int ret;
+
+       ret = clk_prepare_enable(spi100k->ick);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable ick: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(spi100k->fck);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable fck: %d\n", ret);
+               clk_disable_unprepare(spi100k->ick);
+               return ret;
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops omap1_spi100k_pm = {
+       SET_RUNTIME_PM_OPS(omap1_spi100k_runtime_suspend,
+                          omap1_spi100k_runtime_resume, NULL)
+};
+
 static struct platform_driver omap1_spi100k_driver = {
        .driver = {
                .name           = "omap1_spi100k",
+               .pm             = &omap1_spi100k_pm,
        },
        .probe          = omap1_spi100k_probe,
+       .remove         = omap1_spi100k_remove,
 };
 
 module_platform_driver(omap1_spi100k_driver);
index 3c0844457c075d0c5f3ed98fce96dd7951888f05..55576db315497379d73d6f2513b2bbfadb32d2d0 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/module.h>
 #include <linux/io.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
index ee513a85296b19a3c57aad4daef4ec42ee3d90b1..94af80676684e4708d373e1551b8a6c46ea118fa 100644 (file)
  */
 #define DEFAULT_SSP_REG_IMSC  0x0UL
 #define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC
-#define ENABLE_ALL_INTERRUPTS (~DEFAULT_SSP_REG_IMSC)
+#define ENABLE_ALL_INTERRUPTS ( \
+       SSP_IMSC_MASK_RORIM | \
+       SSP_IMSC_MASK_RTIM | \
+       SSP_IMSC_MASK_RXIM | \
+       SSP_IMSC_MASK_TXIM \
+)
 
 #define CLEAR_ALL_INTERRUPTS  0x3
 
@@ -1251,7 +1256,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
        struct pl022 *pl022 = dev_id;
        struct spi_message *msg = pl022->cur_msg;
        u16 irq_status = 0;
-       u16 flag = 0;
 
        if (unlikely(!msg)) {
                dev_err(&pl022->adev->dev,
@@ -1280,9 +1284,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
                if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
                        dev_err(&pl022->adev->dev,
                                "RXFIFO is full\n");
-               if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
-                       dev_err(&pl022->adev->dev,
-                               "TXFIFO is full\n");
 
                /*
                 * Disable and clear interrupts, disable SSP,
@@ -1303,8 +1304,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
 
        readwriter(pl022);
 
-       if ((pl022->tx == pl022->tx_end) && (flag == 0)) {
-               flag = 1;
+       if (pl022->tx == pl022->tx_end) {
                /* Disable Transmit interrupt, enable receive interrupt */
                writew((readw(SSP_IMSC(pl022->virtbase)) &
                       ~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM,
index 6f72ad01e0410257a42bc8739f8962abfbaf3b5e..e3223ac75a7c57d55e1c56e90dfac2aea877f8d5 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");
@@ -67,54 +64,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
 #define LPSS_TX_LOTHRESH_DFLT  160
 #define LPSS_TX_HITHRESH_DFLT  224
 
-struct quark_spi_rate {
-       u32 bitrate;
-       u32 dds_clk_rate;
-       u32 clk_div;
-};
-
-/*
- * '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},
-};
-
 /* Offset from drv_data->lpss_base */
 #define GENERAL_REG            0x08
 #define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
@@ -701,25 +650,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 */
+
+       q2 = DIV_ROUND_CLOSEST(fref2, rate);
+       r2 = abs(fref2 / q2 - rate);
 
-       return quark_spi_rate_table[i-1].bitrate;
+       /*
+        * 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 +778,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)
index 900a91bdb3a897c05143fd25b7689549723be454..d5d7d2235163f9ef8c6430d99544ec7f2c791c6b 100644 (file)
@@ -128,125 +128,11 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int spi_legacy_suspend(struct device *dev, pm_message_t message)
-{
-       int                     value = 0;
-       struct spi_driver       *drv = to_spi_driver(dev->driver);
-
-       /* suspend will stop irqs and dma; no more i/o */
-       if (drv) {
-               if (drv->suspend)
-                       value = drv->suspend(to_spi_device(dev), message);
-               else
-                       dev_dbg(dev, "... can't suspend\n");
-       }
-       return value;
-}
-
-static int spi_legacy_resume(struct device *dev)
-{
-       int                     value = 0;
-       struct spi_driver       *drv = to_spi_driver(dev->driver);
-
-       /* resume may restart the i/o queue */
-       if (drv) {
-               if (drv->resume)
-                       value = drv->resume(to_spi_device(dev));
-               else
-                       dev_dbg(dev, "... can't resume\n");
-       }
-       return value;
-}
-
-static int spi_pm_suspend(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_suspend(dev);
-       else
-               return spi_legacy_suspend(dev, PMSG_SUSPEND);
-}
-
-static int spi_pm_resume(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_resume(dev);
-       else
-               return spi_legacy_resume(dev);
-}
-
-static int spi_pm_freeze(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_freeze(dev);
-       else
-               return spi_legacy_suspend(dev, PMSG_FREEZE);
-}
-
-static int spi_pm_thaw(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_thaw(dev);
-       else
-               return spi_legacy_resume(dev);
-}
-
-static int spi_pm_poweroff(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_poweroff(dev);
-       else
-               return spi_legacy_suspend(dev, PMSG_HIBERNATE);
-}
-
-static int spi_pm_restore(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_restore(dev);
-       else
-               return spi_legacy_resume(dev);
-}
-#else
-#define spi_pm_suspend NULL
-#define spi_pm_resume  NULL
-#define spi_pm_freeze  NULL
-#define spi_pm_thaw    NULL
-#define spi_pm_poweroff        NULL
-#define spi_pm_restore NULL
-#endif
-
-static const struct dev_pm_ops spi_pm = {
-       .suspend = spi_pm_suspend,
-       .resume = spi_pm_resume,
-       .freeze = spi_pm_freeze,
-       .thaw = spi_pm_thaw,
-       .poweroff = spi_pm_poweroff,
-       .restore = spi_pm_restore,
-       SET_RUNTIME_PM_OPS(
-               pm_generic_runtime_suspend,
-               pm_generic_runtime_resume,
-               NULL
-       )
-};
-
 struct bus_type spi_bus_type = {
        .name           = "spi",
        .dev_groups     = spi_dev_groups,
        .match          = spi_match_device,
        .uevent         = spi_uevent,
-       .pm             = &spi_pm,
 };
 EXPORT_SYMBOL_GPL(spi_bus_type);
 
index 478c468454609e9eee1c596dbd6d0cae6b1fb5fd..d673072346f2e0415fd4706c7606d5081f87f686 100644 (file)
@@ -162,8 +162,6 @@ struct spi_transfer;
  * @remove: Unbinds this driver from the spi device
  * @shutdown: Standard shutdown callback used during system state
  *     transitions such as powerdown/halt and kexec
- * @suspend: Standard suspend callback used during system state transitions
- * @resume: Standard resume callback used during system state transitions
  * @driver: SPI device drivers should initialize the name and owner
  *     field of this structure.
  *
@@ -184,8 +182,6 @@ struct spi_driver {
        int                     (*probe)(struct spi_device *spi);
        int                     (*remove)(struct spi_device *spi);
        void                    (*shutdown)(struct spi_device *spi);
-       int                     (*suspend)(struct spi_device *spi, pm_message_t mesg);
-       int                     (*resume)(struct spi_device *spi);
        struct device_driver    driver;
 };