aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/mcbsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/mcbsp.c')
-rw-r--r--arch/arm/plat-omap/mcbsp.c203
1 files changed, 146 insertions, 57 deletions
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index b5a6e178a7f9..d598d9fd65ac 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -27,6 +27,8 @@
27 27
28#include <plat/dma.h> 28#include <plat/dma.h>
29#include <plat/mcbsp.h> 29#include <plat/mcbsp.h>
30#include <plat/omap_device.h>
31#include <linux/pm_runtime.h>
30 32
31/* XXX These "sideways" includes are a sign that something is wrong */ 33/* XXX These "sideways" includes are a sign that something is wrong */
32#include "../mach-omap2/cm2xxx_3xxx.h" 34#include "../mach-omap2/cm2xxx_3xxx.h"
@@ -227,10 +229,83 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config)
227} 229}
228EXPORT_SYMBOL(omap_mcbsp_config); 230EXPORT_SYMBOL(omap_mcbsp_config);
229 231
232/**
233 * omap_mcbsp_dma_params - returns the dma channel number
234 * @id - mcbsp id
235 * @stream - indicates the direction of data flow (rx or tx)
236 *
237 * Returns the dma channel number for the rx channel or tx channel
238 * based on the value of @stream for the requested mcbsp given by @id
239 */
240int omap_mcbsp_dma_ch_params(unsigned int id, unsigned int stream)
241{
242 struct omap_mcbsp *mcbsp;
243
244 if (!omap_mcbsp_check_valid_id(id)) {
245 printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
246 return -ENODEV;
247 }
248 mcbsp = id_to_mcbsp_ptr(id);
249
250 if (stream)
251 return mcbsp->dma_rx_sync;
252 else
253 return mcbsp->dma_tx_sync;
254}
255EXPORT_SYMBOL(omap_mcbsp_dma_ch_params);
256
257/**
258 * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
259 * @id - mcbsp id
260 * @stream - indicates the direction of data flow (rx or tx)
261 *
262 * Returns the address of mcbsp data transmit register or data receive register
263 * to be used by DMA for transferring/receiving data based on the value of
264 * @stream for the requested mcbsp given by @id
265 */
266int omap_mcbsp_dma_reg_params(unsigned int id, unsigned int stream)
267{
268 struct omap_mcbsp *mcbsp;
269 int data_reg;
270
271 if (!omap_mcbsp_check_valid_id(id)) {
272 printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
273 return -ENODEV;
274 }
275 mcbsp = id_to_mcbsp_ptr(id);
276
277 data_reg = mcbsp->phys_dma_base;
278
279 if (mcbsp->mcbsp_config_type < MCBSP_CONFIG_TYPE2) {
280 if (stream)
281 data_reg += OMAP_MCBSP_REG_DRR1;
282 else
283 data_reg += OMAP_MCBSP_REG_DXR1;
284 } else {
285 if (stream)
286 data_reg += OMAP_MCBSP_REG_DRR;
287 else
288 data_reg += OMAP_MCBSP_REG_DXR;
289 }
290
291 return data_reg;
292}
293EXPORT_SYMBOL(omap_mcbsp_dma_reg_params);
294
230#ifdef CONFIG_ARCH_OMAP3 295#ifdef CONFIG_ARCH_OMAP3
296static struct omap_device *find_omap_device_by_dev(struct device *dev)
297{
298 struct platform_device *pdev = container_of(dev,
299 struct platform_device, dev);
300 return container_of(pdev, struct omap_device, pdev);
301}
302
231static void omap_st_on(struct omap_mcbsp *mcbsp) 303static void omap_st_on(struct omap_mcbsp *mcbsp)
232{ 304{
233 unsigned int w; 305 unsigned int w;
306 struct omap_device *od;
307
308 od = find_omap_device_by_dev(mcbsp->dev);
234 309
235 /* 310 /*
236 * Sidetone uses McBSP ICLK - which must not idle when sidetones 311 * Sidetone uses McBSP ICLK - which must not idle when sidetones
@@ -244,9 +319,6 @@ static void omap_st_on(struct omap_mcbsp *mcbsp)
244 w = MCBSP_READ(mcbsp, SSELCR); 319 w = MCBSP_READ(mcbsp, SSELCR);
245 MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); 320 MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
246 321
247 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
248 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
249
250 /* Enable Sidetone from Sidetone Core */ 322 /* Enable Sidetone from Sidetone Core */
251 w = MCBSP_ST_READ(mcbsp, SSELCR); 323 w = MCBSP_ST_READ(mcbsp, SSELCR);
252 MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN); 324 MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
@@ -255,13 +327,13 @@ static void omap_st_on(struct omap_mcbsp *mcbsp)
255static void omap_st_off(struct omap_mcbsp *mcbsp) 327static void omap_st_off(struct omap_mcbsp *mcbsp)
256{ 328{
257 unsigned int w; 329 unsigned int w;
330 struct omap_device *od;
331
332 od = find_omap_device_by_dev(mcbsp->dev);
258 333
259 w = MCBSP_ST_READ(mcbsp, SSELCR); 334 w = MCBSP_ST_READ(mcbsp, SSELCR);
260 MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN)); 335 MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
261 336
262 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
263 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
264
265 w = MCBSP_READ(mcbsp, SSELCR); 337 w = MCBSP_READ(mcbsp, SSELCR);
266 MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); 338 MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
267 339
@@ -273,9 +345,9 @@ static void omap_st_off(struct omap_mcbsp *mcbsp)
273static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir) 345static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
274{ 346{
275 u16 val, i; 347 u16 val, i;
348 struct omap_device *od;
276 349
277 val = MCBSP_ST_READ(mcbsp, SYSCONFIG); 350 od = find_omap_device_by_dev(mcbsp->dev);
278 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, val & ~(ST_AUTOIDLE));
279 351
280 val = MCBSP_ST_READ(mcbsp, SSELCR); 352 val = MCBSP_ST_READ(mcbsp, SSELCR);
281 353
@@ -303,9 +375,9 @@ static void omap_st_chgain(struct omap_mcbsp *mcbsp)
303{ 375{
304 u16 w; 376 u16 w;
305 struct omap_mcbsp_st_data *st_data = mcbsp->st_data; 377 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
378 struct omap_device *od;
306 379
307 w = MCBSP_ST_READ(mcbsp, SYSCONFIG); 380 od = find_omap_device_by_dev(mcbsp->dev);
308 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
309 381
310 w = MCBSP_ST_READ(mcbsp, SSELCR); 382 w = MCBSP_ST_READ(mcbsp, SSELCR);
311 383
@@ -648,48 +720,33 @@ EXPORT_SYMBOL(omap_mcbsp_get_dma_op_mode);
648 720
649static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) 721static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp)
650{ 722{
723 struct omap_device *od;
724
725 od = find_omap_device_by_dev(mcbsp->dev);
651 /* 726 /*
652 * Enable wakup behavior, smart idle and all wakeups 727 * Enable wakup behavior, smart idle and all wakeups
653 * REVISIT: some wakeups may be unnecessary 728 * REVISIT: some wakeups may be unnecessary
654 */ 729 */
655 if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 730 if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
656 u16 syscon; 731 MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
657
658 syscon = MCBSP_READ(mcbsp, SYSCON);
659 syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03));
660
661 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
662 syscon |= (ENAWAKEUP | SIDLEMODE(0x02) |
663 CLOCKACTIVITY(0x02));
664 MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
665 } else {
666 syscon |= SIDLEMODE(0x01);
667 }
668
669 MCBSP_WRITE(mcbsp, SYSCON, syscon);
670 } 732 }
671} 733}
672 734
673static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) 735static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp)
674{ 736{
737 struct omap_device *od;
738
739 od = find_omap_device_by_dev(mcbsp->dev);
740
675 /* 741 /*
676 * Disable wakup behavior, smart idle and all wakeups 742 * Disable wakup behavior, smart idle and all wakeups
677 */ 743 */
678 if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 744 if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
679 u16 syscon;
680
681 syscon = MCBSP_READ(mcbsp, SYSCON);
682 syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03));
683 /* 745 /*
684 * HW bug workaround - If no_idle mode is taken, we need to 746 * HW bug workaround - If no_idle mode is taken, we need to
685 * go to smart_idle before going to always_idle, or the 747 * go to smart_idle before going to always_idle, or the
686 * device will not hit retention anymore. 748 * device will not hit retention anymore.
687 */ 749 */
688 syscon |= SIDLEMODE(0x02);
689 MCBSP_WRITE(mcbsp, SYSCON, syscon);
690
691 syscon &= ~(SIDLEMODE(0x03));
692 MCBSP_WRITE(mcbsp, SYSCON, syscon);
693 750
694 MCBSP_WRITE(mcbsp, WAKEUPEN, 0); 751 MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
695 } 752 }
@@ -764,8 +821,7 @@ int omap_mcbsp_request(unsigned int id)
764 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) 821 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
765 mcbsp->pdata->ops->request(id); 822 mcbsp->pdata->ops->request(id);
766 823
767 clk_enable(mcbsp->iclk); 824 pm_runtime_get_sync(mcbsp->dev);
768 clk_enable(mcbsp->fclk);
769 825
770 /* Do procedure specific to omap34xx arch, if applicable */ 826 /* Do procedure specific to omap34xx arch, if applicable */
771 omap34xx_mcbsp_request(mcbsp); 827 omap34xx_mcbsp_request(mcbsp);
@@ -813,8 +869,7 @@ err_clk_disable:
813 /* Do procedure specific to omap34xx arch, if applicable */ 869 /* Do procedure specific to omap34xx arch, if applicable */
814 omap34xx_mcbsp_free(mcbsp); 870 omap34xx_mcbsp_free(mcbsp);
815 871
816 clk_disable(mcbsp->fclk); 872 pm_runtime_put_sync(mcbsp->dev);
817 clk_disable(mcbsp->iclk);
818 873
819 spin_lock(&mcbsp->lock); 874 spin_lock(&mcbsp->lock);
820 mcbsp->free = true; 875 mcbsp->free = true;
@@ -844,8 +899,7 @@ void omap_mcbsp_free(unsigned int id)
844 /* Do procedure specific to omap34xx arch, if applicable */ 899 /* Do procedure specific to omap34xx arch, if applicable */
845 omap34xx_mcbsp_free(mcbsp); 900 omap34xx_mcbsp_free(mcbsp);
846 901
847 clk_disable(mcbsp->fclk); 902 pm_runtime_put_sync(mcbsp->dev);
848 clk_disable(mcbsp->iclk);
849 903
850 if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) { 904 if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) {
851 /* Free IRQs */ 905 /* Free IRQs */
@@ -1649,7 +1703,8 @@ static const struct attribute_group sidetone_attr_group = {
1649 1703
1650static int __devinit omap_st_add(struct omap_mcbsp *mcbsp) 1704static int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
1651{ 1705{
1652 struct omap_mcbsp_platform_data *pdata = mcbsp->pdata; 1706 struct platform_device *pdev;
1707 struct resource *res;
1653 struct omap_mcbsp_st_data *st_data; 1708 struct omap_mcbsp_st_data *st_data;
1654 int err; 1709 int err;
1655 1710
@@ -1659,7 +1714,10 @@ static int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
1659 goto err1; 1714 goto err1;
1660 } 1715 }
1661 1716
1662 st_data->io_base_st = ioremap(pdata->phys_base_st, SZ_4K); 1717 pdev = container_of(mcbsp->dev, struct platform_device, dev);
1718
1719 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
1720 st_data->io_base_st = ioremap(res->start, resource_size(res));
1663 if (!st_data->io_base_st) { 1721 if (!st_data->io_base_st) {
1664 err = -ENOMEM; 1722 err = -ENOMEM;
1665 goto err2; 1723 goto err2;
@@ -1748,6 +1806,7 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev)
1748 struct omap_mcbsp_platform_data *pdata = pdev->dev.platform_data; 1806 struct omap_mcbsp_platform_data *pdata = pdev->dev.platform_data;
1749 struct omap_mcbsp *mcbsp; 1807 struct omap_mcbsp *mcbsp;
1750 int id = pdev->id - 1; 1808 int id = pdev->id - 1;
1809 struct resource *res;
1751 int ret = 0; 1810 int ret = 0;
1752 1811
1753 if (!pdata) { 1812 if (!pdata) {
@@ -1777,47 +1836,78 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev)
1777 mcbsp->dma_tx_lch = -1; 1836 mcbsp->dma_tx_lch = -1;
1778 mcbsp->dma_rx_lch = -1; 1837 mcbsp->dma_rx_lch = -1;
1779 1838
1780 mcbsp->phys_base = pdata->phys_base; 1839 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
1781 mcbsp->io_base = ioremap(pdata->phys_base, SZ_4K); 1840 if (!res) {
1841 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1842 if (!res) {
1843 dev_err(&pdev->dev, "%s:mcbsp%d has invalid memory"
1844 "resource\n", __func__, pdev->id);
1845 ret = -ENOMEM;
1846 goto exit;
1847 }
1848 }
1849 mcbsp->phys_base = res->start;
1850 omap_mcbsp_cache_size = resource_size(res);
1851 mcbsp->io_base = ioremap(res->start, resource_size(res));
1782 if (!mcbsp->io_base) { 1852 if (!mcbsp->io_base) {
1783 ret = -ENOMEM; 1853 ret = -ENOMEM;
1784 goto err_ioremap; 1854 goto err_ioremap;
1785 } 1855 }
1786 1856
1857 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
1858 if (!res)
1859 mcbsp->phys_dma_base = mcbsp->phys_base;
1860 else
1861 mcbsp->phys_dma_base = res->start;
1862
1787 /* Default I/O is IRQ based */ 1863 /* Default I/O is IRQ based */
1788 mcbsp->io_type = OMAP_MCBSP_IRQ_IO; 1864 mcbsp->io_type = OMAP_MCBSP_IRQ_IO;
1789 mcbsp->tx_irq = pdata->tx_irq;
1790 mcbsp->rx_irq = pdata->rx_irq;
1791 mcbsp->dma_rx_sync = pdata->dma_rx_sync;
1792 mcbsp->dma_tx_sync = pdata->dma_tx_sync;
1793 1865
1794 mcbsp->iclk = clk_get(&pdev->dev, "ick"); 1866 mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
1795 if (IS_ERR(mcbsp->iclk)) { 1867 mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
1796 ret = PTR_ERR(mcbsp->iclk); 1868
1797 dev_err(&pdev->dev, "unable to get ick: %d\n", ret); 1869 /* From OMAP4 there will be a single irq line */
1798 goto err_iclk; 1870 if (mcbsp->tx_irq == -ENXIO)
1871 mcbsp->tx_irq = platform_get_irq(pdev, 0);
1872
1873 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
1874 if (!res) {
1875 dev_err(&pdev->dev, "%s:mcbsp%d has invalid rx DMA channel\n",
1876 __func__, pdev->id);
1877 ret = -ENODEV;
1878 goto err_res;
1879 }
1880 mcbsp->dma_rx_sync = res->start;
1881
1882 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
1883 if (!res) {
1884 dev_err(&pdev->dev, "%s:mcbsp%d has invalid tx DMA channel\n",
1885 __func__, pdev->id);
1886 ret = -ENODEV;
1887 goto err_res;
1799 } 1888 }
1889 mcbsp->dma_tx_sync = res->start;
1800 1890
1801 mcbsp->fclk = clk_get(&pdev->dev, "fck"); 1891 mcbsp->fclk = clk_get(&pdev->dev, "fck");
1802 if (IS_ERR(mcbsp->fclk)) { 1892 if (IS_ERR(mcbsp->fclk)) {
1803 ret = PTR_ERR(mcbsp->fclk); 1893 ret = PTR_ERR(mcbsp->fclk);
1804 dev_err(&pdev->dev, "unable to get fck: %d\n", ret); 1894 dev_err(&pdev->dev, "unable to get fck: %d\n", ret);
1805 goto err_fclk; 1895 goto err_res;
1806 } 1896 }
1807 1897
1808 mcbsp->pdata = pdata; 1898 mcbsp->pdata = pdata;
1809 mcbsp->dev = &pdev->dev; 1899 mcbsp->dev = &pdev->dev;
1810 mcbsp_ptr[id] = mcbsp; 1900 mcbsp_ptr[id] = mcbsp;
1901 mcbsp->mcbsp_config_type = pdata->mcbsp_config_type;
1811 platform_set_drvdata(pdev, mcbsp); 1902 platform_set_drvdata(pdev, mcbsp);
1903 pm_runtime_enable(mcbsp->dev);
1812 1904
1813 /* Initialize mcbsp properties for OMAP34XX if needed / applicable */ 1905 /* Initialize mcbsp properties for OMAP34XX if needed / applicable */
1814 omap34xx_device_init(mcbsp); 1906 omap34xx_device_init(mcbsp);
1815 1907
1816 return 0; 1908 return 0;
1817 1909
1818err_fclk: 1910err_res:
1819 clk_put(mcbsp->iclk);
1820err_iclk:
1821 iounmap(mcbsp->io_base); 1911 iounmap(mcbsp->io_base);
1822err_ioremap: 1912err_ioremap:
1823 kfree(mcbsp); 1913 kfree(mcbsp);
@@ -1839,7 +1929,6 @@ static int __devexit omap_mcbsp_remove(struct platform_device *pdev)
1839 omap34xx_device_exit(mcbsp); 1929 omap34xx_device_exit(mcbsp);
1840 1930
1841 clk_put(mcbsp->fclk); 1931 clk_put(mcbsp->fclk);
1842 clk_put(mcbsp->iclk);
1843 1932
1844 iounmap(mcbsp->io_base); 1933 iounmap(mcbsp->io_base);
1845 kfree(mcbsp); 1934 kfree(mcbsp);