diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-29 10:28:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-29 10:28:36 -0400 |
commit | 18c0635363364ca2fc2d1cbd65bbf918daf89d1a (patch) | |
tree | 6fd1975977b4ab190b77952ee8e263f66e3dc5f7 /drivers/spi/spi-pl022.c | |
parent | 41684f67af75b04152a1714e1a5375dfb00ee3da (diff) | |
parent | 940ab88962bc1aff3273a8356d64577a6e386736 (diff) |
Merge branch 'spi/next' of git://git.secretlab.ca/git/linux-2.6
* '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
Diffstat (limited to 'drivers/spi/spi-pl022.c')
-rw-r--r-- | drivers/spi/spi-pl022.c | 146 |
1 files changed, 68 insertions, 78 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 1ab2fa0d37f..f103e470cb6 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c | |||
@@ -113,7 +113,6 @@ | |||
113 | #define SSP_CR0_MASK_CSS_ST (0x1FUL << 16) | 113 | #define SSP_CR0_MASK_CSS_ST (0x1FUL << 16) |
114 | #define SSP_CR0_MASK_FRF_ST (0x3UL << 21) | 114 | #define SSP_CR0_MASK_FRF_ST (0x3UL << 21) |
115 | 115 | ||
116 | |||
117 | /* | 116 | /* |
118 | * SSP Control Register 0 - SSP_CR1 | 117 | * SSP Control Register 0 - SSP_CR1 |
119 | */ | 118 | */ |
@@ -283,7 +282,6 @@ | |||
283 | 282 | ||
284 | #define SPI_POLLING_TIMEOUT 1000 | 283 | #define SPI_POLLING_TIMEOUT 1000 |
285 | 284 | ||
286 | |||
287 | /* | 285 | /* |
288 | * The type of reading going on on this chip | 286 | * The type of reading going on on this chip |
289 | */ | 287 | */ |
@@ -749,7 +747,6 @@ static void readwriter(struct pl022 *pl022) | |||
749 | */ | 747 | */ |
750 | } | 748 | } |
751 | 749 | ||
752 | |||
753 | /** | 750 | /** |
754 | * next_transfer - Move to the Next transfer in the current spi message | 751 | * next_transfer - Move to the Next transfer in the current spi message |
755 | * @pl022: SSP driver private data structure | 752 | * @pl022: SSP driver private data structure |
@@ -1016,14 +1013,14 @@ static int configure_dma(struct pl022 *pl022) | |||
1016 | dmaengine_slave_config(txchan, &tx_conf); | 1013 | dmaengine_slave_config(txchan, &tx_conf); |
1017 | 1014 | ||
1018 | /* Create sglists for the transfers */ | 1015 | /* Create sglists for the transfers */ |
1019 | pages = (pl022->cur_transfer->len >> PAGE_SHIFT) + 1; | 1016 | pages = DIV_ROUND_UP(pl022->cur_transfer->len, PAGE_SIZE); |
1020 | dev_dbg(&pl022->adev->dev, "using %d pages for transfer\n", pages); | 1017 | dev_dbg(&pl022->adev->dev, "using %d pages for transfer\n", pages); |
1021 | 1018 | ||
1022 | ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_KERNEL); | 1019 | ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_ATOMIC); |
1023 | if (ret) | 1020 | if (ret) |
1024 | goto err_alloc_rx_sg; | 1021 | goto err_alloc_rx_sg; |
1025 | 1022 | ||
1026 | ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_KERNEL); | 1023 | ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_ATOMIC); |
1027 | if (ret) | 1024 | if (ret) |
1028 | goto err_alloc_tx_sg; | 1025 | goto err_alloc_tx_sg; |
1029 | 1026 | ||
@@ -1531,8 +1528,7 @@ static void pump_messages(struct work_struct *work) | |||
1531 | /* Initial message state */ | 1528 | /* Initial message state */ |
1532 | pl022->cur_msg->state = STATE_START; | 1529 | pl022->cur_msg->state = STATE_START; |
1533 | pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next, | 1530 | pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next, |
1534 | struct spi_transfer, | 1531 | struct spi_transfer, transfer_list); |
1535 | transfer_list); | ||
1536 | 1532 | ||
1537 | /* Setup the SPI using the per chip configuration */ | 1533 | /* Setup the SPI using the per chip configuration */ |
1538 | pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi); | 1534 | pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi); |
@@ -1551,7 +1547,6 @@ static void pump_messages(struct work_struct *work) | |||
1551 | do_interrupt_dma_transfer(pl022); | 1547 | do_interrupt_dma_transfer(pl022); |
1552 | } | 1548 | } |
1553 | 1549 | ||
1554 | |||
1555 | static int __init init_queue(struct pl022 *pl022) | 1550 | static int __init init_queue(struct pl022 *pl022) |
1556 | { | 1551 | { |
1557 | INIT_LIST_HEAD(&pl022->queue); | 1552 | INIT_LIST_HEAD(&pl022->queue); |
@@ -1560,8 +1555,8 @@ static int __init init_queue(struct pl022 *pl022) | |||
1560 | pl022->running = false; | 1555 | pl022->running = false; |
1561 | pl022->busy = false; | 1556 | pl022->busy = false; |
1562 | 1557 | ||
1563 | tasklet_init(&pl022->pump_transfers, | 1558 | tasklet_init(&pl022->pump_transfers, pump_transfers, |
1564 | pump_transfers, (unsigned long)pl022); | 1559 | (unsigned long)pl022); |
1565 | 1560 | ||
1566 | INIT_WORK(&pl022->pump_messages, pump_messages); | 1561 | INIT_WORK(&pl022->pump_messages, pump_messages); |
1567 | pl022->workqueue = create_singlethread_workqueue( | 1562 | pl022->workqueue = create_singlethread_workqueue( |
@@ -1572,7 +1567,6 @@ static int __init init_queue(struct pl022 *pl022) | |||
1572 | return 0; | 1567 | return 0; |
1573 | } | 1568 | } |
1574 | 1569 | ||
1575 | |||
1576 | static int start_queue(struct pl022 *pl022) | 1570 | static int start_queue(struct pl022 *pl022) |
1577 | { | 1571 | { |
1578 | unsigned long flags; | 1572 | unsigned long flags; |
@@ -1595,7 +1589,6 @@ static int start_queue(struct pl022 *pl022) | |||
1595 | return 0; | 1589 | return 0; |
1596 | } | 1590 | } |
1597 | 1591 | ||
1598 | |||
1599 | static int stop_queue(struct pl022 *pl022) | 1592 | static int stop_queue(struct pl022 *pl022) |
1600 | { | 1593 | { |
1601 | unsigned long flags; | 1594 | unsigned long flags; |
@@ -1791,71 +1784,70 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg) | |||
1791 | return 0; | 1784 | return 0; |
1792 | } | 1785 | } |
1793 | 1786 | ||
1794 | static int calculate_effective_freq(struct pl022 *pl022, | 1787 | static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr) |
1795 | int freq, | 1788 | { |
1796 | struct ssp_clock_params *clk_freq) | 1789 | return rate / (cpsdvsr * (1 + scr)); |
1790 | } | ||
1791 | |||
1792 | static int calculate_effective_freq(struct pl022 *pl022, int freq, struct | ||
1793 | ssp_clock_params * clk_freq) | ||
1797 | { | 1794 | { |
1798 | /* Lets calculate the frequency parameters */ | 1795 | /* Lets calculate the frequency parameters */ |
1799 | u16 cpsdvsr = 2; | 1796 | u16 cpsdvsr = CPSDVR_MIN, scr = SCR_MIN; |
1800 | u16 scr = 0; | 1797 | u32 rate, max_tclk, min_tclk, best_freq = 0, best_cpsdvsr = 0, |
1801 | bool freq_found = false; | 1798 | best_scr = 0, tmp, found = 0; |
1802 | u32 rate; | ||
1803 | u32 max_tclk; | ||
1804 | u32 min_tclk; | ||
1805 | 1799 | ||
1806 | rate = clk_get_rate(pl022->clk); | 1800 | rate = clk_get_rate(pl022->clk); |
1807 | /* cpsdvscr = 2 & scr 0 */ | 1801 | /* cpsdvscr = 2 & scr 0 */ |
1808 | max_tclk = (rate / (CPSDVR_MIN * (1 + SCR_MIN))); | 1802 | max_tclk = spi_rate(rate, CPSDVR_MIN, SCR_MIN); |
1809 | /* cpsdvsr = 254 & scr = 255 */ | 1803 | /* cpsdvsr = 254 & scr = 255 */ |
1810 | min_tclk = (rate / (CPSDVR_MAX * (1 + SCR_MAX))); | 1804 | min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX); |
1811 | 1805 | ||
1812 | if ((freq <= max_tclk) && (freq >= min_tclk)) { | 1806 | if (!((freq <= max_tclk) && (freq >= min_tclk))) { |
1813 | while (cpsdvsr <= CPSDVR_MAX && !freq_found) { | ||
1814 | while (scr <= SCR_MAX && !freq_found) { | ||
1815 | if ((rate / | ||
1816 | (cpsdvsr * (1 + scr))) > freq) | ||
1817 | scr += 1; | ||
1818 | else { | ||
1819 | /* | ||
1820 | * This bool is made true when | ||
1821 | * effective frequency >= | ||
1822 | * target frequency is found | ||
1823 | */ | ||
1824 | freq_found = true; | ||
1825 | if ((rate / | ||
1826 | (cpsdvsr * (1 + scr))) != freq) { | ||
1827 | if (scr == SCR_MIN) { | ||
1828 | cpsdvsr -= 2; | ||
1829 | scr = SCR_MAX; | ||
1830 | } else | ||
1831 | scr -= 1; | ||
1832 | } | ||
1833 | } | ||
1834 | } | ||
1835 | if (!freq_found) { | ||
1836 | cpsdvsr += 2; | ||
1837 | scr = SCR_MIN; | ||
1838 | } | ||
1839 | } | ||
1840 | if (cpsdvsr != 0) { | ||
1841 | dev_dbg(&pl022->adev->dev, | ||
1842 | "SSP Effective Frequency is %u\n", | ||
1843 | (rate / (cpsdvsr * (1 + scr)))); | ||
1844 | clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF); | ||
1845 | clk_freq->scr = (u8) (scr & 0xFF); | ||
1846 | dev_dbg(&pl022->adev->dev, | ||
1847 | "SSP cpsdvsr = %d, scr = %d\n", | ||
1848 | clk_freq->cpsdvsr, clk_freq->scr); | ||
1849 | } | ||
1850 | } else { | ||
1851 | dev_err(&pl022->adev->dev, | 1807 | dev_err(&pl022->adev->dev, |
1852 | "controller data is incorrect: out of range frequency"); | 1808 | "controller data is incorrect: out of range frequency"); |
1853 | return -EINVAL; | 1809 | return -EINVAL; |
1854 | } | 1810 | } |
1811 | |||
1812 | /* | ||
1813 | * best_freq will give closest possible available rate (<= requested | ||
1814 | * freq) for all values of scr & cpsdvsr. | ||
1815 | */ | ||
1816 | while ((cpsdvsr <= CPSDVR_MAX) && !found) { | ||
1817 | while (scr <= SCR_MAX) { | ||
1818 | tmp = spi_rate(rate, cpsdvsr, scr); | ||
1819 | |||
1820 | if (tmp > freq) | ||
1821 | scr++; | ||
1822 | /* | ||
1823 | * If found exact value, update and break. | ||
1824 | * If found more closer value, update and continue. | ||
1825 | */ | ||
1826 | else if ((tmp == freq) || (tmp > best_freq)) { | ||
1827 | best_freq = tmp; | ||
1828 | best_cpsdvsr = cpsdvsr; | ||
1829 | best_scr = scr; | ||
1830 | |||
1831 | if (tmp == freq) | ||
1832 | break; | ||
1833 | } | ||
1834 | scr++; | ||
1835 | } | ||
1836 | cpsdvsr += 2; | ||
1837 | scr = SCR_MIN; | ||
1838 | } | ||
1839 | |||
1840 | clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF); | ||
1841 | clk_freq->scr = (u8) (best_scr & 0xFF); | ||
1842 | dev_dbg(&pl022->adev->dev, | ||
1843 | "SSP Target Frequency is: %u, Effective Frequency is %u\n", | ||
1844 | freq, best_freq); | ||
1845 | dev_dbg(&pl022->adev->dev, "SSP cpsdvsr = %d, scr = %d\n", | ||
1846 | clk_freq->cpsdvsr, clk_freq->scr); | ||
1847 | |||
1855 | return 0; | 1848 | return 0; |
1856 | } | 1849 | } |
1857 | 1850 | ||
1858 | |||
1859 | /* | 1851 | /* |
1860 | * A piece of default chip info unless the platform | 1852 | * A piece of default chip info unless the platform |
1861 | * supplies it. | 1853 | * supplies it. |
@@ -1873,7 +1865,6 @@ static const struct pl022_config_chip pl022_default_chip_info = { | |||
1873 | .cs_control = null_cs_control, | 1865 | .cs_control = null_cs_control, |
1874 | }; | 1866 | }; |
1875 | 1867 | ||
1876 | |||
1877 | /** | 1868 | /** |
1878 | * pl022_setup - setup function registered to SPI master framework | 1869 | * pl022_setup - setup function registered to SPI master framework |
1879 | * @spi: spi device which is requesting setup | 1870 | * @spi: spi device which is requesting setup |
@@ -1950,7 +1941,6 @@ static int pl022_setup(struct spi_device *spi) | |||
1950 | goto err_config_params; | 1941 | goto err_config_params; |
1951 | } | 1942 | } |
1952 | 1943 | ||
1953 | |||
1954 | status = verify_controller_parameters(pl022, chip_info); | 1944 | status = verify_controller_parameters(pl022, chip_info); |
1955 | if (status) { | 1945 | if (status) { |
1956 | dev_err(&spi->dev, "controller data is incorrect"); | 1946 | dev_err(&spi->dev, "controller data is incorrect"); |
@@ -2090,7 +2080,8 @@ static int pl022_setup(struct spi_device *spi) | |||
2090 | } | 2080 | } |
2091 | SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1); | 2081 | SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1); |
2092 | SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2); | 2082 | SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2); |
2093 | SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3); | 2083 | SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, |
2084 | 3); | ||
2094 | 2085 | ||
2095 | /* Save controller_state */ | 2086 | /* Save controller_state */ |
2096 | spi_set_ctldata(spi, chip); | 2087 | spi_set_ctldata(spi, chip); |
@@ -2116,7 +2107,6 @@ static void pl022_cleanup(struct spi_device *spi) | |||
2116 | kfree(chip); | 2107 | kfree(chip); |
2117 | } | 2108 | } |
2118 | 2109 | ||
2119 | |||
2120 | static int __devinit | 2110 | static int __devinit |
2121 | pl022_probe(struct amba_device *adev, const struct amba_id *id) | 2111 | pl022_probe(struct amba_device *adev, const struct amba_id *id) |
2122 | { | 2112 | { |
@@ -2242,7 +2232,9 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2242 | err_start_queue: | 2232 | err_start_queue: |
2243 | err_init_queue: | 2233 | err_init_queue: |
2244 | destroy_queue(pl022); | 2234 | destroy_queue(pl022); |
2245 | pl022_dma_remove(pl022); | 2235 | if (platform_info->enable_dma) |
2236 | pl022_dma_remove(pl022); | ||
2237 | |||
2246 | free_irq(adev->irq[0], pl022); | 2238 | free_irq(adev->irq[0], pl022); |
2247 | err_no_irq: | 2239 | err_no_irq: |
2248 | clk_unprepare(pl022->clk); | 2240 | clk_unprepare(pl022->clk); |
@@ -2277,7 +2269,9 @@ pl022_remove(struct amba_device *adev) | |||
2277 | if (destroy_queue(pl022) != 0) | 2269 | if (destroy_queue(pl022) != 0) |
2278 | dev_err(&adev->dev, "queue remove failed\n"); | 2270 | dev_err(&adev->dev, "queue remove failed\n"); |
2279 | load_ssp_default_config(pl022); | 2271 | load_ssp_default_config(pl022); |
2280 | pl022_dma_remove(pl022); | 2272 | if (pl022->master_info->enable_dma) |
2273 | pl022_dma_remove(pl022); | ||
2274 | |||
2281 | free_irq(adev->irq[0], pl022); | 2275 | free_irq(adev->irq[0], pl022); |
2282 | clk_disable(pl022->clk); | 2276 | clk_disable(pl022->clk); |
2283 | clk_unprepare(pl022->clk); | 2277 | clk_unprepare(pl022->clk); |
@@ -2364,7 +2358,6 @@ static struct vendor_data vendor_arm = { | |||
2364 | .loopback = true, | 2358 | .loopback = true, |
2365 | }; | 2359 | }; |
2366 | 2360 | ||
2367 | |||
2368 | static struct vendor_data vendor_st = { | 2361 | static struct vendor_data vendor_st = { |
2369 | .fifodepth = 32, | 2362 | .fifodepth = 32, |
2370 | .max_bpw = 32, | 2363 | .max_bpw = 32, |
@@ -2419,9 +2412,9 @@ static struct amba_id pl022_ids[] = { | |||
2419 | * and 32 locations deep TX/RX FIFO but no extended | 2412 | * and 32 locations deep TX/RX FIFO but no extended |
2420 | * CR0/CR1 register | 2413 | * CR0/CR1 register |
2421 | */ | 2414 | */ |
2422 | .id = 0x00080023, | 2415 | .id = 0x00080023, |
2423 | .mask = 0xffffffff, | 2416 | .mask = 0xffffffff, |
2424 | .data = &vendor_st_pl023, | 2417 | .data = &vendor_st_pl023, |
2425 | }, | 2418 | }, |
2426 | { | 2419 | { |
2427 | .id = 0x10080023, | 2420 | .id = 0x10080023, |
@@ -2441,19 +2434,16 @@ static struct amba_driver pl022_driver = { | |||
2441 | .remove = __devexit_p(pl022_remove), | 2434 | .remove = __devexit_p(pl022_remove), |
2442 | }; | 2435 | }; |
2443 | 2436 | ||
2444 | |||
2445 | static int __init pl022_init(void) | 2437 | static int __init pl022_init(void) |
2446 | { | 2438 | { |
2447 | return amba_driver_register(&pl022_driver); | 2439 | return amba_driver_register(&pl022_driver); |
2448 | } | 2440 | } |
2449 | |||
2450 | subsys_initcall(pl022_init); | 2441 | subsys_initcall(pl022_init); |
2451 | 2442 | ||
2452 | static void __exit pl022_exit(void) | 2443 | static void __exit pl022_exit(void) |
2453 | { | 2444 | { |
2454 | amba_driver_unregister(&pl022_driver); | 2445 | amba_driver_unregister(&pl022_driver); |
2455 | } | 2446 | } |
2456 | |||
2457 | module_exit(pl022_exit); | 2447 | module_exit(pl022_exit); |
2458 | 2448 | ||
2459 | MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); | 2449 | MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); |