15e742ad6SRussell King /* 25e742ad6SRussell King * linux/drivers/mfd/mcp-sa11x0.c 35e742ad6SRussell King * 45e742ad6SRussell King * Copyright (C) 2001-2005 Russell King 55e742ad6SRussell King * 65e742ad6SRussell King * This program is free software; you can redistribute it and/or modify 75e742ad6SRussell King * it under the terms of the GNU General Public License as published by 85e742ad6SRussell King * the Free Software Foundation; either version 2 of the License. 95e742ad6SRussell King * 105e742ad6SRussell King * SA11x0 MCP (Multimedia Communications Port) driver. 115e742ad6SRussell King * 125e742ad6SRussell King * MCP read/write timeouts from Jordi Colomer, rehacked by rmk. 135e742ad6SRussell King */ 145e742ad6SRussell King #include <linux/module.h> 155e742ad6SRussell King #include <linux/init.h> 165e742ad6SRussell King #include <linux/errno.h> 175e742ad6SRussell King #include <linux/kernel.h> 185e742ad6SRussell King #include <linux/delay.h> 195e742ad6SRussell King #include <linux/spinlock.h> 20d052d1beSRussell King #include <linux/platform_device.h> 21c8602edfSThomas Kunze #include <linux/mfd/mcp.h> 225e742ad6SRussell King 23dcea83adSRussell King #include <mach/dma.h> 24a09e64fbSRussell King #include <mach/hardware.h> 255e742ad6SRussell King #include <asm/mach-types.h> 265e742ad6SRussell King #include <asm/system.h> 27a09e64fbSRussell King #include <mach/mcp.h> 285e742ad6SRussell King 29*216f63c4SRussell King #include <mach/assabet.h> 30*216f63c4SRussell King 315e742ad6SRussell King 325e742ad6SRussell King struct mcp_sa11x0 { 335e742ad6SRussell King u32 mccr0; 345e742ad6SRussell King u32 mccr1; 355e742ad6SRussell King }; 365e742ad6SRussell King 375e742ad6SRussell King #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp)) 385e742ad6SRussell King 395e742ad6SRussell King static void 405e742ad6SRussell King mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) 415e742ad6SRussell King { 42*216f63c4SRussell King unsigned int mccr0; 435e742ad6SRussell King 445e742ad6SRussell King divisor /= 32; 455e742ad6SRussell King 46*216f63c4SRussell King mccr0 = Ser4MCCR0 & ~0x00007f00; 47*216f63c4SRussell King mccr0 |= divisor << 8; 48*216f63c4SRussell King Ser4MCCR0 = mccr0; 495e742ad6SRussell King } 505e742ad6SRussell King 515e742ad6SRussell King static void 525e742ad6SRussell King mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) 535e742ad6SRussell King { 54*216f63c4SRussell King unsigned int mccr0; 555e742ad6SRussell King 565e742ad6SRussell King divisor /= 32; 575e742ad6SRussell King 58*216f63c4SRussell King mccr0 = Ser4MCCR0 & ~0x0000007f; 59*216f63c4SRussell King mccr0 |= divisor; 60*216f63c4SRussell King Ser4MCCR0 = mccr0; 615e742ad6SRussell King } 625e742ad6SRussell King 635e742ad6SRussell King /* 645e742ad6SRussell King * Write data to the device. The bit should be set after 3 subframe 655e742ad6SRussell King * times (each frame is 64 clocks). We wait a maximum of 6 subframes. 665e742ad6SRussell King * We really should try doing something more productive while we 675e742ad6SRussell King * wait. 685e742ad6SRussell King */ 695e742ad6SRussell King static void 705e742ad6SRussell King mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) 715e742ad6SRussell King { 725e742ad6SRussell King int ret = -ETIME; 735e742ad6SRussell King int i; 745e742ad6SRussell King 75*216f63c4SRussell King Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff); 765e742ad6SRussell King 775e742ad6SRussell King for (i = 0; i < 2; i++) { 785e742ad6SRussell King udelay(mcp->rw_timeout); 79*216f63c4SRussell King if (Ser4MCSR & MCSR_CWC) { 805e742ad6SRussell King ret = 0; 815e742ad6SRussell King break; 825e742ad6SRussell King } 835e742ad6SRussell King } 845e742ad6SRussell King 855e742ad6SRussell King if (ret < 0) 865e742ad6SRussell King printk(KERN_WARNING "mcp: write timed out\n"); 875e742ad6SRussell King } 885e742ad6SRussell King 895e742ad6SRussell King /* 905e742ad6SRussell King * Read data from the device. The bit should be set after 3 subframe 915e742ad6SRussell King * times (each frame is 64 clocks). We wait a maximum of 6 subframes. 925e742ad6SRussell King * We really should try doing something more productive while we 935e742ad6SRussell King * wait. 945e742ad6SRussell King */ 955e742ad6SRussell King static unsigned int 965e742ad6SRussell King mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) 975e742ad6SRussell King { 985e742ad6SRussell King int ret = -ETIME; 995e742ad6SRussell King int i; 1005e742ad6SRussell King 101*216f63c4SRussell King Ser4MCDR2 = reg << 17 | MCDR2_Rd; 1025e742ad6SRussell King 1035e742ad6SRussell King for (i = 0; i < 2; i++) { 1045e742ad6SRussell King udelay(mcp->rw_timeout); 105*216f63c4SRussell King if (Ser4MCSR & MCSR_CRC) { 106*216f63c4SRussell King ret = Ser4MCDR2 & 0xffff; 1075e742ad6SRussell King break; 1085e742ad6SRussell King } 1095e742ad6SRussell King } 1105e742ad6SRussell King 1115e742ad6SRussell King if (ret < 0) 1125e742ad6SRussell King printk(KERN_WARNING "mcp: read timed out\n"); 1135e742ad6SRussell King 1145e742ad6SRussell King return ret; 1155e742ad6SRussell King } 1165e742ad6SRussell King 1175e742ad6SRussell King static void mcp_sa11x0_enable(struct mcp *mcp) 1185e742ad6SRussell King { 119*216f63c4SRussell King Ser4MCSR = -1; 120*216f63c4SRussell King Ser4MCCR0 |= MCCR0_MCE; 1215e742ad6SRussell King } 1225e742ad6SRussell King 1235e742ad6SRussell King static void mcp_sa11x0_disable(struct mcp *mcp) 1245e742ad6SRussell King { 125*216f63c4SRussell King Ser4MCCR0 &= ~MCCR0_MCE; 1265e742ad6SRussell King } 1275e742ad6SRussell King 1285e742ad6SRussell King /* 1295e742ad6SRussell King * Our methods. 1305e742ad6SRussell King */ 1315e742ad6SRussell King static struct mcp_ops mcp_sa11x0 = { 1325e742ad6SRussell King .set_telecom_divisor = mcp_sa11x0_set_telecom_divisor, 1335e742ad6SRussell King .set_audio_divisor = mcp_sa11x0_set_audio_divisor, 1345e742ad6SRussell King .reg_write = mcp_sa11x0_write, 1355e742ad6SRussell King .reg_read = mcp_sa11x0_read, 1365e742ad6SRussell King .enable = mcp_sa11x0_enable, 1375e742ad6SRussell King .disable = mcp_sa11x0_disable, 1385e742ad6SRussell King }; 1395e742ad6SRussell King 1403ae5eaecSRussell King static int mcp_sa11x0_probe(struct platform_device *pdev) 1415e742ad6SRussell King { 142323cdfc1SRussell King struct mcp_plat_data *data = pdev->dev.platform_data; 1435e742ad6SRussell King struct mcp *mcp; 1445e742ad6SRussell King int ret; 1455e742ad6SRussell King 146323cdfc1SRussell King if (!data) 1475e742ad6SRussell King return -ENODEV; 1485e742ad6SRussell King 1495dd7bf59SJochen Friedrich if (!data->codec) 1505dd7bf59SJochen Friedrich return -ENODEV; 1515dd7bf59SJochen Friedrich 152*216f63c4SRussell King if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) 1535e742ad6SRussell King return -EBUSY; 1545e742ad6SRussell King 1555e742ad6SRussell King mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0)); 1565e742ad6SRussell King if (!mcp) { 1575e742ad6SRussell King ret = -ENOMEM; 158*216f63c4SRussell King goto release; 1595e742ad6SRussell King } 1605e742ad6SRussell King 1615e742ad6SRussell King mcp->owner = THIS_MODULE; 1625e742ad6SRussell King mcp->ops = &mcp_sa11x0; 163323cdfc1SRussell King mcp->sclk_rate = data->sclk_rate; 164*216f63c4SRussell King mcp->dma_audio_rd = DMA_Ser4MCP0Rd; 165*216f63c4SRussell King mcp->dma_audio_wr = DMA_Ser4MCP0Wr; 166*216f63c4SRussell King mcp->dma_telco_rd = DMA_Ser4MCP1Rd; 167*216f63c4SRussell King mcp->dma_telco_wr = DMA_Ser4MCP1Wr; 1685dd7bf59SJochen Friedrich mcp->codec = data->codec; 1695e742ad6SRussell King 1703ae5eaecSRussell King platform_set_drvdata(pdev, mcp); 1715e742ad6SRussell King 172*216f63c4SRussell King if (machine_is_assabet()) { 173*216f63c4SRussell King ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); 174*216f63c4SRussell King } 175*216f63c4SRussell King 176*216f63c4SRussell King /* 177*216f63c4SRussell King * Setup the PPC unit correctly. 178*216f63c4SRussell King */ 179*216f63c4SRussell King PPDR &= ~PPC_RXD4; 180*216f63c4SRussell King PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; 181*216f63c4SRussell King PSDR |= PPC_RXD4; 182*216f63c4SRussell King PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); 183*216f63c4SRussell King PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); 184*216f63c4SRussell King 185323cdfc1SRussell King /* 186323cdfc1SRussell King * Initialise device. Note that we initially 187323cdfc1SRussell King * set the sampling rate to minimum. 188323cdfc1SRussell King */ 189*216f63c4SRussell King Ser4MCSR = -1; 190*216f63c4SRussell King Ser4MCCR1 = data->mccr1; 191*216f63c4SRussell King Ser4MCCR0 = data->mccr0 | 0x7f7f; 1925e742ad6SRussell King 1935e742ad6SRussell King /* 1945e742ad6SRussell King * Calculate the read/write timeout (us) from the bit clock 1955e742ad6SRussell King * rate. This is the period for 3 64-bit frames. Always 1965e742ad6SRussell King * round this time up. 1975e742ad6SRussell King */ 1985e742ad6SRussell King mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / 1995e742ad6SRussell King mcp->sclk_rate; 2005e742ad6SRussell King 2015dd7bf59SJochen Friedrich ret = mcp_host_register(mcp, data->codec_pdata); 2025e742ad6SRussell King if (ret == 0) 2035e742ad6SRussell King goto out; 2045e742ad6SRussell King 2055e742ad6SRussell King release: 206*216f63c4SRussell King release_mem_region(0x80060000, 0x60); 2073ae5eaecSRussell King platform_set_drvdata(pdev, NULL); 2085e742ad6SRussell King 2095e742ad6SRussell King out: 2105e742ad6SRussell King return ret; 2115e742ad6SRussell King } 2125e742ad6SRussell King 213*216f63c4SRussell King static int mcp_sa11x0_remove(struct platform_device *dev) 2145e742ad6SRussell King { 215*216f63c4SRussell King struct mcp *mcp = platform_get_drvdata(dev); 2165e742ad6SRussell King 217*216f63c4SRussell King platform_set_drvdata(dev, NULL); 2185e742ad6SRussell King mcp_host_unregister(mcp); 219*216f63c4SRussell King release_mem_region(0x80060000, 0x60); 2205e742ad6SRussell King 2215e742ad6SRussell King return 0; 2225e742ad6SRussell King } 2235e742ad6SRussell King 2243ae5eaecSRussell King static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) 2255e742ad6SRussell King { 2263ae5eaecSRussell King struct mcp *mcp = platform_get_drvdata(dev); 2275e742ad6SRussell King 228*216f63c4SRussell King priv(mcp)->mccr0 = Ser4MCCR0; 229*216f63c4SRussell King priv(mcp)->mccr1 = Ser4MCCR1; 230*216f63c4SRussell King Ser4MCCR0 &= ~MCCR0_MCE; 2319480e307SRussell King 2325e742ad6SRussell King return 0; 2335e742ad6SRussell King } 2345e742ad6SRussell King 2353ae5eaecSRussell King static int mcp_sa11x0_resume(struct platform_device *dev) 2365e742ad6SRussell King { 2373ae5eaecSRussell King struct mcp *mcp = platform_get_drvdata(dev); 2385e742ad6SRussell King 239*216f63c4SRussell King Ser4MCCR1 = priv(mcp)->mccr1; 240*216f63c4SRussell King Ser4MCCR0 = priv(mcp)->mccr0; 2419480e307SRussell King 2425e742ad6SRussell King return 0; 2435e742ad6SRussell King } 2445e742ad6SRussell King 2455e742ad6SRussell King /* 2465e742ad6SRussell King * The driver for the SA11x0 MCP port. 2475e742ad6SRussell King */ 2484f46d6e7SKay Sievers MODULE_ALIAS("platform:sa11x0-mcp"); 2494f46d6e7SKay Sievers 2503ae5eaecSRussell King static struct platform_driver mcp_sa11x0_driver = { 2515e742ad6SRussell King .probe = mcp_sa11x0_probe, 2525e742ad6SRussell King .remove = mcp_sa11x0_remove, 2535e742ad6SRussell King .suspend = mcp_sa11x0_suspend, 2545e742ad6SRussell King .resume = mcp_sa11x0_resume, 2553ae5eaecSRussell King .driver = { 2563ae5eaecSRussell King .name = "sa11x0-mcp", 2573ae5eaecSRussell King }, 2585e742ad6SRussell King }; 2595e742ad6SRussell King 2605e742ad6SRussell King /* 2615e742ad6SRussell King * This needs re-working 2625e742ad6SRussell King */ 26365349d60SMark Brown module_platform_driver(mcp_sa11x0_driver); 2645e742ad6SRussell King 2655e742ad6SRussell King MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); 2665e742ad6SRussell King MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); 2675e742ad6SRussell King MODULE_LICENSE("GPL"); 268