1 /* 2 * linux/arch/arm/mach-omap1/mcbsp.c 3 * 4 * Copyright (C) 2008 Instituto Nokia de Tecnologia 5 * Contact: Eduardo Valentin <eduardo.valentin@indt.org.br> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * Multichannel mode not supported. 12 */ 13 #include <linux/module.h> 14 #include <linux/init.h> 15 #include <linux/clk.h> 16 #include <linux/err.h> 17 #include <linux/io.h> 18 #include <linux/platform_device.h> 19 20 #include <asm/arch/dma.h> 21 #include <asm/arch/mux.h> 22 #include <asm/arch/cpu.h> 23 #include <asm/arch/mcbsp.h> 24 #include <asm/arch/dsp_common.h> 25 26 #define DPS_RSTCT2_PER_EN (1 << 0) 27 #define DSP_RSTCT2_WD_PER_EN (1 << 1) 28 29 struct mcbsp_internal_clk { 30 struct clk clk; 31 struct clk **childs; 32 int n_childs; 33 }; 34 35 #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) 36 static void omap_mcbsp_clk_init(struct mcbsp_internal_clk *mclk) 37 { 38 const char *clk_names[] = { "dsp_ck", "api_ck", "dspxor_ck" }; 39 int i; 40 41 mclk->n_childs = ARRAY_SIZE(clk_names); 42 mclk->childs = kzalloc(mclk->n_childs * sizeof(struct clk *), 43 GFP_KERNEL); 44 45 for (i = 0; i < mclk->n_childs; i++) { 46 /* We fake a platform device to get correct device id */ 47 struct platform_device pdev; 48 49 pdev.dev.bus = &platform_bus_type; 50 pdev.id = mclk->clk.id; 51 mclk->childs[i] = clk_get(&pdev.dev, clk_names[i]); 52 if (IS_ERR(mclk->childs[i])) 53 printk(KERN_ERR "Could not get clock %s (%d).\n", 54 clk_names[i], mclk->clk.id); 55 } 56 } 57 58 static int omap_mcbsp_clk_enable(struct clk *clk) 59 { 60 struct mcbsp_internal_clk *mclk = container_of(clk, 61 struct mcbsp_internal_clk, clk); 62 int i; 63 64 for (i = 0; i < mclk->n_childs; i++) 65 clk_enable(mclk->childs[i]); 66 return 0; 67 } 68 69 static void omap_mcbsp_clk_disable(struct clk *clk) 70 { 71 struct mcbsp_internal_clk *mclk = container_of(clk, 72 struct mcbsp_internal_clk, clk); 73 int i; 74 75 for (i = 0; i < mclk->n_childs; i++) 76 clk_disable(mclk->childs[i]); 77 } 78 79 static struct mcbsp_internal_clk omap_mcbsp_clks[] = { 80 { 81 .clk = { 82 .name = "mcbsp_clk", 83 .id = 1, 84 .enable = omap_mcbsp_clk_enable, 85 .disable = omap_mcbsp_clk_disable, 86 }, 87 }, 88 { 89 .clk = { 90 .name = "mcbsp_clk", 91 .id = 3, 92 .enable = omap_mcbsp_clk_enable, 93 .disable = omap_mcbsp_clk_disable, 94 }, 95 }, 96 }; 97 98 #define omap_mcbsp_clks_size ARRAY_SIZE(omap_mcbsp_clks) 99 #else 100 #define omap_mcbsp_clks_size 0 101 static struct mcbsp_internal_clk __initdata *omap_mcbsp_clks; 102 static inline void omap_mcbsp_clk_init(struct mcbsp_internal_clk *mclk) 103 { } 104 #endif 105 106 static int omap1_mcbsp_check(unsigned int id) 107 { 108 /* REVISIT: Check correctly for number of registered McBSPs */ 109 if (cpu_is_omap730()) { 110 if (id > OMAP_MAX_MCBSP_COUNT - 2) { 111 printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", 112 id + 1); 113 return -ENODEV; 114 } 115 return 0; 116 } 117 118 if (cpu_is_omap15xx() || cpu_is_omap16xx()) { 119 if (id > OMAP_MAX_MCBSP_COUNT - 1) { 120 printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", 121 id + 1); 122 return -ENODEV; 123 } 124 return 0; 125 } 126 127 return -ENODEV; 128 } 129 130 static void omap1_mcbsp_request(unsigned int id) 131 { 132 /* 133 * On 1510, 1610 and 1710, McBSP1 and McBSP3 134 * are DSP public peripherals. 135 */ 136 if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) { 137 omap_dsp_request_mem(); 138 /* 139 * DSP external peripheral reset 140 * FIXME: This should be moved to dsp code 141 */ 142 __raw_writew(__raw_readw(DSP_RSTCT2) | DPS_RSTCT2_PER_EN | 143 DSP_RSTCT2_WD_PER_EN, DSP_RSTCT2); 144 } 145 } 146 147 static void omap1_mcbsp_free(unsigned int id) 148 { 149 if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) 150 omap_dsp_release_mem(); 151 } 152 153 static struct omap_mcbsp_ops omap1_mcbsp_ops = { 154 .check = omap1_mcbsp_check, 155 .request = omap1_mcbsp_request, 156 .free = omap1_mcbsp_free, 157 }; 158 159 #ifdef CONFIG_ARCH_OMAP730 160 static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = { 161 { 162 .virt_base = io_p2v(OMAP730_MCBSP1_BASE), 163 .dma_rx_sync = OMAP_DMA_MCBSP1_RX, 164 .dma_tx_sync = OMAP_DMA_MCBSP1_TX, 165 .rx_irq = INT_730_McBSP1RX, 166 .tx_irq = INT_730_McBSP1TX, 167 .ops = &omap1_mcbsp_ops, 168 }, 169 { 170 .virt_base = io_p2v(OMAP730_MCBSP2_BASE), 171 .dma_rx_sync = OMAP_DMA_MCBSP3_RX, 172 .dma_tx_sync = OMAP_DMA_MCBSP3_TX, 173 .rx_irq = INT_730_McBSP2RX, 174 .tx_irq = INT_730_McBSP2TX, 175 .ops = &omap1_mcbsp_ops, 176 }, 177 }; 178 #define OMAP730_MCBSP_PDATA_SZ ARRAY_SIZE(omap730_mcbsp_pdata) 179 #else 180 #define omap730_mcbsp_pdata NULL 181 #define OMAP730_MCBSP_PDATA_SZ 0 182 #endif 183 184 #ifdef CONFIG_ARCH_OMAP15XX 185 static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = { 186 { 187 .virt_base = OMAP1510_MCBSP1_BASE, 188 .dma_rx_sync = OMAP_DMA_MCBSP1_RX, 189 .dma_tx_sync = OMAP_DMA_MCBSP1_TX, 190 .rx_irq = INT_McBSP1RX, 191 .tx_irq = INT_McBSP1TX, 192 .ops = &omap1_mcbsp_ops, 193 .clk_name = "mcbsp_clk", 194 }, 195 { 196 .virt_base = io_p2v(OMAP1510_MCBSP2_BASE), 197 .dma_rx_sync = OMAP_DMA_MCBSP2_RX, 198 .dma_tx_sync = OMAP_DMA_MCBSP2_TX, 199 .rx_irq = INT_1510_SPI_RX, 200 .tx_irq = INT_1510_SPI_TX, 201 .ops = &omap1_mcbsp_ops, 202 }, 203 { 204 .virt_base = OMAP1510_MCBSP3_BASE, 205 .dma_rx_sync = OMAP_DMA_MCBSP3_RX, 206 .dma_tx_sync = OMAP_DMA_MCBSP3_TX, 207 .rx_irq = INT_McBSP3RX, 208 .tx_irq = INT_McBSP3TX, 209 .ops = &omap1_mcbsp_ops, 210 .clk_name = "mcbsp_clk", 211 }, 212 }; 213 #define OMAP15XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap15xx_mcbsp_pdata) 214 #else 215 #define omap15xx_mcbsp_pdata NULL 216 #define OMAP15XX_MCBSP_PDATA_SZ 0 217 #endif 218 219 #ifdef CONFIG_ARCH_OMAP16XX 220 static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = { 221 { 222 .virt_base = OMAP1610_MCBSP1_BASE, 223 .dma_rx_sync = OMAP_DMA_MCBSP1_RX, 224 .dma_tx_sync = OMAP_DMA_MCBSP1_TX, 225 .rx_irq = INT_McBSP1RX, 226 .tx_irq = INT_McBSP1TX, 227 .ops = &omap1_mcbsp_ops, 228 .clk_name = "mcbsp_clk", 229 }, 230 { 231 .virt_base = io_p2v(OMAP1610_MCBSP2_BASE), 232 .dma_rx_sync = OMAP_DMA_MCBSP2_RX, 233 .dma_tx_sync = OMAP_DMA_MCBSP2_TX, 234 .rx_irq = INT_1610_McBSP2_RX, 235 .tx_irq = INT_1610_McBSP2_TX, 236 .ops = &omap1_mcbsp_ops, 237 }, 238 { 239 .virt_base = OMAP1610_MCBSP3_BASE, 240 .dma_rx_sync = OMAP_DMA_MCBSP3_RX, 241 .dma_tx_sync = OMAP_DMA_MCBSP3_TX, 242 .rx_irq = INT_McBSP3RX, 243 .tx_irq = INT_McBSP3TX, 244 .ops = &omap1_mcbsp_ops, 245 .clk_name = "mcbsp_clk", 246 }, 247 }; 248 #define OMAP16XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap16xx_mcbsp_pdata) 249 #else 250 #define omap16xx_mcbsp_pdata NULL 251 #define OMAP16XX_MCBSP_PDATA_SZ 0 252 #endif 253 254 int __init omap1_mcbsp_init(void) 255 { 256 int i; 257 258 for (i = 0; i < omap_mcbsp_clks_size; i++) { 259 if (cpu_is_omap15xx() || cpu_is_omap16xx()) { 260 omap_mcbsp_clk_init(&omap_mcbsp_clks[i]); 261 clk_register(&omap_mcbsp_clks[i].clk); 262 } 263 } 264 265 if (cpu_is_omap730()) 266 omap_mcbsp_register_board_cfg(omap730_mcbsp_pdata, 267 OMAP730_MCBSP_PDATA_SZ); 268 269 if (cpu_is_omap15xx()) 270 omap_mcbsp_register_board_cfg(omap15xx_mcbsp_pdata, 271 OMAP15XX_MCBSP_PDATA_SZ); 272 273 if (cpu_is_omap16xx()) 274 omap_mcbsp_register_board_cfg(omap16xx_mcbsp_pdata, 275 OMAP16XX_MCBSP_PDATA_SZ); 276 277 return omap_mcbsp_init(); 278 } 279 280 arch_initcall(omap1_mcbsp_init); 281