]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'spi/next' of git://git.secretlab.ca/git/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Oct 2011 14:28:36 +0000 (07:28 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Oct 2011 14:28:36 +0000 (07:28 -0700)
* 'spi/next' of git://git.secretlab.ca/git/linux-2.6:
  drivercore: Add helper macro for platform_driver boilerplate
  spi: irq: Remove IRQF_DISABLED
  OMAP: SPI: Fix the trying to free nonexistent resource error
  spi/spi-ep93xx: add module.h include
  spi/tegra: fix compilation error in spi-tegra.c
  spi: spi-dw: fix all sparse warnings
  spi/spi-pl022: Call pl022_dma_remove(pl022) only if enable_dma is true
  spi/spi-pl022: calculate_effective_freq() must set rate <= requested rate
  spi/spi-pl022: Don't allocate more sg than required.
  spi/spi-pl022: Use GFP_ATOMIC for allocation from tasklet
  spi/spi-pl022: Resolve formatting issues

1  2 
drivers/spi/spi-atmel.c
drivers/spi/spi-pl022.c
include/linux/platform_device.h

diff --combined drivers/spi/spi-atmel.c
index d3bff424286f109c6fcb1f0956096e604b0c0459,a356392ab2f6bd9d537c4459c83d66ed2794447d..79665e2e6ec524b89f02c6aa680ca5b133009fa9
@@@ -22,7 -22,7 +22,7 @@@
  
  #include <asm/io.h>
  #include <mach/board.h>
 -#include <mach/gpio.h>
 +#include <asm/gpio.h>
  #include <mach/cpu.h>
  
  /* SPI register offsets */
@@@ -1074,18 -1074,7 +1074,7 @@@ static struct platform_driver atmel_spi
        .resume         = atmel_spi_resume,
        .remove         = __exit_p(atmel_spi_remove),
  };
- static int __init atmel_spi_init(void)
- {
-       return platform_driver_probe(&atmel_spi_driver, atmel_spi_probe);
- }
- module_init(atmel_spi_init);
- static void __exit atmel_spi_exit(void)
- {
-       platform_driver_unregister(&atmel_spi_driver);
- }
- module_exit(atmel_spi_exit);
+ module_platform_driver(atmel_spi_driver);
  
  MODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver");
  MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
diff --combined drivers/spi/spi-pl022.c
index 1ab2fa0d37fd7d0d6dea52e0dd801cbd8a4cea52,c828dc607d998cc47216f037fdd5853c73ef7b43..f103e470cb6362e248a264576e457e03f0ab5409
  #define SSP_CR0_MASK_CSS_ST   (0x1FUL << 16)
  #define SSP_CR0_MASK_FRF_ST   (0x3UL << 21)
  
  /*
   * SSP Control Register 0  - SSP_CR1
   */
  
  #define SPI_POLLING_TIMEOUT 1000
  
  /*
   * The type of reading going on on this chip
   */
@@@ -515,6 -513,9 +513,6 @@@ static void giveback(struct pl022 *pl02
        if (msg->complete)
                msg->complete(msg->context);
        /* This message is completed, so let's turn off the clocks & power */
 -      clk_disable(pl022->clk);
 -      amba_pclk_disable(pl022->adev);
 -      amba_vcore_disable(pl022->adev);
        pm_runtime_put(&pl022->adev->dev);
  }
  
@@@ -749,7 -750,6 +747,6 @@@ static void readwriter(struct pl022 *pl
         */
  }
  
  /**
   * next_transfer - Move to the Next transfer in the current spi message
   * @pl022: SSP driver private data structure
@@@ -1016,14 -1016,14 +1013,14 @@@ static int configure_dma(struct pl022 *
        dmaengine_slave_config(txchan, &tx_conf);
  
        /* Create sglists for the transfers */
-       pages = (pl022->cur_transfer->len >> PAGE_SHIFT) + 1;
+       pages = DIV_ROUND_UP(pl022->cur_transfer->len, PAGE_SIZE);
        dev_dbg(&pl022->adev->dev, "using %d pages for transfer\n", pages);
  
-       ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_KERNEL);
+       ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_ATOMIC);
        if (ret)
                goto err_alloc_rx_sg;
  
-       ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_KERNEL);
+       ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_ATOMIC);
        if (ret)
                goto err_alloc_tx_sg;
  
@@@ -1531,8 -1531,7 +1528,7 @@@ static void pump_messages(struct work_s
        /* Initial message state */
        pl022->cur_msg->state = STATE_START;
        pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next,
-                                           struct spi_transfer,
-                                           transfer_list);
+                                           struct spi_transfer, transfer_list);
  
        /* Setup the SPI using the per chip configuration */
        pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
         * (poll/interrupt/DMA)
         */
        pm_runtime_get_sync(&pl022->adev->dev);
 -      amba_vcore_enable(pl022->adev);
 -      amba_pclk_enable(pl022->adev);
 -      clk_enable(pl022->clk);
        restore_state(pl022);
        flush(pl022);
  
                do_interrupt_dma_transfer(pl022);
  }
  
  static int __init init_queue(struct pl022 *pl022)
  {
        INIT_LIST_HEAD(&pl022->queue);
        pl022->running = false;
        pl022->busy = false;
  
-       tasklet_init(&pl022->pump_transfers,
-                       pump_transfers, (unsigned long)pl022);
+       tasklet_init(&pl022->pump_transfers, pump_transfers,
+                       (unsigned long)pl022);
  
        INIT_WORK(&pl022->pump_messages, pump_messages);
        pl022->workqueue = create_singlethread_workqueue(
        return 0;
  }
  
  static int start_queue(struct pl022 *pl022)
  {
        unsigned long flags;
        return 0;
  }
  
  static int stop_queue(struct pl022 *pl022)
  {
        unsigned long flags;
@@@ -1791,71 -1790,70 +1784,70 @@@ static int pl022_transfer(struct spi_de
        return 0;
  }
  
- static int calculate_effective_freq(struct pl022 *pl022,
-                                   int freq,
-                                   struct ssp_clock_params *clk_freq)
+ static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr)
+ {
+       return rate / (cpsdvsr * (1 + scr));
+ }
+ static int calculate_effective_freq(struct pl022 *pl022, int freq, struct
+                                   ssp_clock_params * clk_freq)
  {
        /* Lets calculate the frequency parameters */
-       u16 cpsdvsr = 2;
-       u16 scr = 0;
-       bool freq_found = false;
-       u32 rate;
-       u32 max_tclk;
-       u32 min_tclk;
+       u16 cpsdvsr = CPSDVR_MIN, scr = SCR_MIN;
+       u32 rate, max_tclk, min_tclk, best_freq = 0, best_cpsdvsr = 0,
+               best_scr = 0, tmp, found = 0;
  
        rate = clk_get_rate(pl022->clk);
        /* cpsdvscr = 2 & scr 0 */
-       max_tclk = (rate / (CPSDVR_MIN * (1 + SCR_MIN)));
+       max_tclk = spi_rate(rate, CPSDVR_MIN, SCR_MIN);
        /* cpsdvsr = 254 & scr = 255 */
-       min_tclk = (rate / (CPSDVR_MAX * (1 + SCR_MAX)));
-       if ((freq <= max_tclk) && (freq >= min_tclk)) {
-               while (cpsdvsr <= CPSDVR_MAX && !freq_found) {
-                       while (scr <= SCR_MAX && !freq_found) {
-                               if ((rate /
-                                    (cpsdvsr * (1 + scr))) > freq)
-                                       scr += 1;
-                               else {
-                                       /*
-                                        * This bool is made true when
-                                        * effective frequency >=
-                                        * target frequency is found
-                                        */
-                                       freq_found = true;
-                                       if ((rate /
-                                            (cpsdvsr * (1 + scr))) != freq) {
-                                               if (scr == SCR_MIN) {
-                                                       cpsdvsr -= 2;
-                                                       scr = SCR_MAX;
-                                               } else
-                                                       scr -= 1;
-                                       }
-                               }
-                       }
-                       if (!freq_found) {
-                               cpsdvsr += 2;
-                               scr = SCR_MIN;
-                       }
-               }
-               if (cpsdvsr != 0) {
-                       dev_dbg(&pl022->adev->dev,
-                               "SSP Effective Frequency is %u\n",
-                               (rate / (cpsdvsr * (1 + scr))));
-                       clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF);
-                       clk_freq->scr = (u8) (scr & 0xFF);
-                       dev_dbg(&pl022->adev->dev,
-                               "SSP cpsdvsr = %d, scr = %d\n",
-                               clk_freq->cpsdvsr, clk_freq->scr);
-               }
-       } else {
+       min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX);
+       if (!((freq <= max_tclk) && (freq >= min_tclk))) {
                dev_err(&pl022->adev->dev,
                        "controller data is incorrect: out of range frequency");
                return -EINVAL;
        }
+       /*
+        * best_freq will give closest possible available rate (<= requested
+        * freq) for all values of scr & cpsdvsr.
+        */
+       while ((cpsdvsr <= CPSDVR_MAX) && !found) {
+               while (scr <= SCR_MAX) {
+                       tmp = spi_rate(rate, cpsdvsr, scr);
+                       if (tmp > freq)
+                               scr++;
+                       /*
+                        * If found exact value, update and break.
+                        * If found more closer value, update and continue.
+                        */
+                       else if ((tmp == freq) || (tmp > best_freq)) {
+                               best_freq = tmp;
+                               best_cpsdvsr = cpsdvsr;
+                               best_scr = scr;
+                               if (tmp == freq)
+                                       break;
+                       }
+                       scr++;
+               }
+               cpsdvsr += 2;
+               scr = SCR_MIN;
+       }
+       clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF);
+       clk_freq->scr = (u8) (best_scr & 0xFF);
+       dev_dbg(&pl022->adev->dev,
+               "SSP Target Frequency is: %u, Effective Frequency is %u\n",
+               freq, best_freq);
+       dev_dbg(&pl022->adev->dev, "SSP cpsdvsr = %d, scr = %d\n",
+               clk_freq->cpsdvsr, clk_freq->scr);
        return 0;
  }
  
  /*
   * A piece of default chip info unless the platform
   * supplies it.
@@@ -1873,7 -1871,6 +1865,6 @@@ static const struct pl022_config_chip p
        .cs_control = null_cs_control,
  };
  
  /**
   * pl022_setup - setup function registered to SPI master framework
   * @spi: spi device which is requesting setup
@@@ -1950,7 -1947,6 +1941,6 @@@ static int pl022_setup(struct spi_devic
                goto err_config_params;
        }
  
        status = verify_controller_parameters(pl022, chip_info);
        if (status) {
                dev_err(&spi->dev, "controller data is incorrect");
        }
        SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
        SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
-       SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3);
+       SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD,
+               3);
  
        /* Save controller_state */
        spi_set_ctldata(spi, chip);
@@@ -2116,7 -2113,6 +2107,6 @@@ static void pl022_cleanup(struct spi_de
        kfree(chip);
  }
  
  static int __devinit
  pl022_probe(struct amba_device *adev, const struct amba_id *id)
  {
        }
        printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n",
               adev->res.start, pl022->virtbase);
 -      pm_runtime_enable(dev);
 -      pm_runtime_resume(dev);
  
        pl022->clk = clk_get(&adev->dev, NULL);
        if (IS_ERR(pl022->clk)) {
                goto err_no_clk;
        }
  
 +      status = clk_prepare(pl022->clk);
 +      if (status) {
 +              dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n");
 +              goto  err_clk_prep;
 +      }
 +
        /* Disable SSP */
        writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
               SSP_CR1(pl022->virtbase));
                goto err_spi_register;
        }
        dev_dbg(dev, "probe succeeded\n");
 -      /*
 -       * Disable the silicon block pclk and any voltage domain and just
 -       * power it up and clock it when it's needed
 -       */
 -      amba_pclk_disable(adev);
 -      amba_vcore_disable(adev);
 +
 +      /* let runtime pm put suspend */
 +      pm_runtime_put(dev);
        return 0;
  
   err_spi_register:
   err_start_queue:
   err_init_queue:
        destroy_queue(pl022);
-       pl022_dma_remove(pl022);
+       if (platform_info->enable_dma)
+               pl022_dma_remove(pl022);
        free_irq(adev->irq[0], pl022);
 -      pm_runtime_disable(&adev->dev);
   err_no_irq:
 +      clk_unprepare(pl022->clk);
 + err_clk_prep:
        clk_put(pl022->clk);
   err_no_clk:
        iounmap(pl022->virtbase);
@@@ -2267,20 -2263,15 +2259,22 @@@ pl022_remove(struct amba_device *adev
        if (!pl022)
                return 0;
  
 +      /*
 +       * undo pm_runtime_put() in probe.  I assume that we're not
 +       * accessing the primecell here.
 +       */
 +      pm_runtime_get_noresume(&adev->dev);
 +
        /* Remove the queue */
        if (destroy_queue(pl022) != 0)
                dev_err(&adev->dev, "queue remove failed\n");
        load_ssp_default_config(pl022);
-       pl022_dma_remove(pl022);
+       if (pl022->master_info->enable_dma)
+               pl022_dma_remove(pl022);
        free_irq(adev->irq[0], pl022);
        clk_disable(pl022->clk);
 +      clk_unprepare(pl022->clk);
        clk_put(pl022->clk);
        iounmap(pl022->virtbase);
        amba_release_regions(adev);
        return 0;
  }
  
 -#ifdef CONFIG_PM
 -static int pl022_suspend(struct amba_device *adev, pm_message_t state)
 +#ifdef CONFIG_SUSPEND
 +static int pl022_suspend(struct device *dev)
  {
 -      struct pl022 *pl022 = amba_get_drvdata(adev);
 +      struct pl022 *pl022 = dev_get_drvdata(dev);
        int status = 0;
  
        status = stop_queue(pl022);
        if (status) {
 -              dev_warn(&adev->dev, "suspend cannot stop queue\n");
 +              dev_warn(dev, "suspend cannot stop queue\n");
                return status;
        }
  
 -      amba_vcore_enable(adev);
 -      amba_pclk_enable(adev);
 +      amba_vcore_enable(pl022->adev);
 +      amba_pclk_enable(pl022->adev);
        load_ssp_default_config(pl022);
 -      amba_pclk_disable(adev);
 -      amba_vcore_disable(adev);
 -      dev_dbg(&adev->dev, "suspended\n");
 +      amba_pclk_disable(pl022->adev);
 +      amba_vcore_disable(pl022->adev);
 +      dev_dbg(dev, "suspended\n");
        return 0;
  }
  
 -static int pl022_resume(struct amba_device *adev)
 +static int pl022_resume(struct device *dev)
  {
 -      struct pl022 *pl022 = amba_get_drvdata(adev);
 +      struct pl022 *pl022 = dev_get_drvdata(dev);
        int status = 0;
  
        /* Start the queue running */
        status = start_queue(pl022);
        if (status)
 -              dev_err(&adev->dev, "problem starting queue (%d)\n", status);
 +              dev_err(dev, "problem starting queue (%d)\n", status);
        else
 -              dev_dbg(&adev->dev, "resumed\n");
 +              dev_dbg(dev, "resumed\n");
  
        return status;
  }
 -#else
 -#define pl022_suspend NULL
 -#define pl022_resume NULL
  #endif        /* CONFIG_PM */
  
 +#ifdef CONFIG_PM_RUNTIME
 +static int pl022_runtime_suspend(struct device *dev)
 +{
 +      struct pl022 *pl022 = dev_get_drvdata(dev);
 +
 +      clk_disable(pl022->clk);
 +      amba_vcore_disable(pl022->adev);
 +
 +      return 0;
 +}
 +
 +static int pl022_runtime_resume(struct device *dev)
 +{
 +      struct pl022 *pl022 = dev_get_drvdata(dev);
 +
 +      amba_vcore_enable(pl022->adev);
 +      clk_enable(pl022->clk);
 +
 +      return 0;
 +}
 +#endif
 +
 +static const struct dev_pm_ops pl022_dev_pm_ops = {
 +      SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
 +      SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
 +};
 +
  static struct vendor_data vendor_arm = {
        .fifodepth = 8,
        .max_bpw = 16,
        .loopback = true,
  };
  
  static struct vendor_data vendor_st = {
        .fifodepth = 32,
        .max_bpw = 32,
@@@ -2419,9 -2385,9 +2412,9 @@@ static struct amba_id pl022_ids[] = 
                 * and 32 locations deep TX/RX FIFO but no extended
                 * CR0/CR1 register
                 */
-               .id     = 0x00080023,
-               .mask   = 0xffffffff,
-               .data   = &vendor_st_pl023,
+               .id     = 0x00080023,
+               .mask   = 0xffffffff,
+               .data   = &vendor_st_pl023,
        },
        {
                .id     = 0x10080023,
  static struct amba_driver pl022_driver = {
        .drv = {
                .name   = "ssp-pl022",
 +              .pm     = &pl022_dev_pm_ops,
        },
        .id_table       = pl022_ids,
        .probe          = pl022_probe,
        .remove         = __devexit_p(pl022_remove),
 -      .suspend        = pl022_suspend,
 -      .resume         = pl022_resume,
  };
  
  static int __init pl022_init(void)
  {
        return amba_driver_register(&pl022_driver);
  }
  subsys_initcall(pl022_init);
  
  static void __exit pl022_exit(void)
  {
        amba_driver_unregister(&pl022_driver);
  }
  module_exit(pl022_exit);
  
  MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
index 651a066686ac6a40e52f7f1229bc14735d430b64,08de528afd6603d6cdb1888102c83b14ef19966d..2a23f7d1a8252807055d58f29f8d0833c75ed999
@@@ -49,54 -49,10 +49,54 @@@ extern struct resource *platform_get_re
  extern int platform_get_irq_byname(struct platform_device *, const char *);
  extern int platform_add_devices(struct platform_device **, int);
  
 -extern struct platform_device *platform_device_register_resndata(
 +struct platform_device_info {
 +              struct device *parent;
 +
 +              const char *name;
 +              int id;
 +
 +              const struct resource *res;
 +              unsigned int num_res;
 +
 +              const void *data;
 +              size_t size_data;
 +              u64 dma_mask;
 +};
 +extern struct platform_device *platform_device_register_full(
 +              struct platform_device_info *pdevinfo);
 +
 +/**
 + * platform_device_register_resndata - add a platform-level device with
 + * resources and platform-specific data
 + *
 + * @parent: parent device for the device we're adding
 + * @name: base name of the device we're adding
 + * @id: instance id
 + * @res: set of resources that needs to be allocated for the device
 + * @num: number of resources
 + * @data: platform specific data for this platform device
 + * @size: size of platform specific data
 + *
 + * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
 + */
 +static inline struct platform_device *platform_device_register_resndata(
                struct device *parent, const char *name, int id,
                const struct resource *res, unsigned int num,
 -              const void *data, size_t size);
 +              const void *data, size_t size) {
 +
 +      struct platform_device_info pdevinfo = {
 +              .parent = parent,
 +              .name = name,
 +              .id = id,
 +              .res = res,
 +              .num_res = num,
 +              .data = data,
 +              .size_data = size,
 +              .dma_mask = 0,
 +      };
 +
 +      return platform_device_register_full(&pdevinfo);
 +}
  
  /**
   * platform_device_register_simple - add a platform-level device and its resources
@@@ -190,6 -146,23 +190,23 @@@ static inline void platform_set_drvdata
        dev_set_drvdata(&pdev->dev, data);
  }
  
+ /* module_platform_driver() - Helper macro for drivers that don't do
+  * anything special in module init/exit.  This eliminates a lot of
+  * boilerplate.  Each module may only use this macro once, and
+  * calling it replaces module_init() and module_exit()
+  */
+ #define module_platform_driver(__platform_driver) \
+ static int __init __platform_driver##_init(void) \
+ { \
+       return platform_driver_register(&(__platform_driver)); \
+ } \
+ module_init(__platform_driver##_init); \
+ static void __exit __platform_driver##_exit(void) \
+ { \
+       platform_driver_unregister(&(__platform_driver)); \
+ } \
+ module_exit(__platform_driver##_exit);
  extern struct platform_device *platform_create_bundle(struct platform_driver *driver,
                                        int (*probe)(struct platform_device *),
                                        struct resource *res, unsigned int n_res,