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 <mach/dma.h> 21 #include <mach/mux.h> 22 #include <mach/cpu.h> 23 #include <mach/mcbsp.h> 24 #include <mach/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 void omap1_mcbsp_request(unsigned int id) 107 { 108 /* 109 * On 1510, 1610 and 1710, McBSP1 and McBSP3 110 * are DSP public peripherals. 111 */ 112 if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) { 113 omap_dsp_request_mem(); 114 /* 115 * DSP external peripheral reset 116 * FIXME: This should be moved to dsp code 117 */ 118 __raw_writew(__raw_readw(DSP_RSTCT2) | DPS_RSTCT2_PER_EN | 119 DSP_RSTCT2_WD_PER_EN, DSP_RSTCT2); 120 } 121 } 122 123 static void omap1_mcbsp_free(unsigned int id) 124 { 125 if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) 126 omap_dsp_release_mem(); 127 } 128 129 static struct omap_mcbsp_ops omap1_mcbsp_ops = { 130 .request = omap1_mcbsp_request, 131 .free = omap1_mcbsp_free, 132 }; 133 134 #ifdef CONFIG_ARCH_OMAP730 135 static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = { 136 { 137 .phys_base = OMAP730_MCBSP1_BASE, 138 .dma_rx_sync = OMAP_DMA_MCBSP1_RX, 139 .dma_tx_sync = OMAP_DMA_MCBSP1_TX, 140 .rx_irq = INT_730_McBSP1RX, 141 .tx_irq = INT_730_McBSP1TX, 142 .ops = &omap1_mcbsp_ops, 143 }, 144 { 145 .phys_base = OMAP730_MCBSP2_BASE, 146 .dma_rx_sync = OMAP_DMA_MCBSP3_RX, 147 .dma_tx_sync = OMAP_DMA_MCBSP3_TX, 148 .rx_irq = INT_730_McBSP2RX, 149 .tx_irq = INT_730_McBSP2TX, 150 .ops = &omap1_mcbsp_ops, 151 }, 152 }; 153 #define OMAP730_MCBSP_PDATA_SZ ARRAY_SIZE(omap730_mcbsp_pdata) 154 #else 155 #define omap730_mcbsp_pdata NULL 156 #define OMAP730_MCBSP_PDATA_SZ 0 157 #endif 158 159 #ifdef CONFIG_ARCH_OMAP15XX 160 static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = { 161 { 162 .phys_base = OMAP1510_MCBSP1_BASE, 163 .dma_rx_sync = OMAP_DMA_MCBSP1_RX, 164 .dma_tx_sync = OMAP_DMA_MCBSP1_TX, 165 .rx_irq = INT_McBSP1RX, 166 .tx_irq = INT_McBSP1TX, 167 .ops = &omap1_mcbsp_ops, 168 .clk_name = "mcbsp_clk", 169 }, 170 { 171 .phys_base = OMAP1510_MCBSP2_BASE, 172 .dma_rx_sync = OMAP_DMA_MCBSP2_RX, 173 .dma_tx_sync = OMAP_DMA_MCBSP2_TX, 174 .rx_irq = INT_1510_SPI_RX, 175 .tx_irq = INT_1510_SPI_TX, 176 .ops = &omap1_mcbsp_ops, 177 }, 178 { 179 .phys_base = OMAP1510_MCBSP3_BASE, 180 .dma_rx_sync = OMAP_DMA_MCBSP3_RX, 181 .dma_tx_sync = OMAP_DMA_MCBSP3_TX, 182 .rx_irq = INT_McBSP3RX, 183 .tx_irq = INT_McBSP3TX, 184 .ops = &omap1_mcbsp_ops, 185 .clk_name = "mcbsp_clk", 186 }, 187 }; 188 #define OMAP15XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap15xx_mcbsp_pdata) 189 #else 190 #define omap15xx_mcbsp_pdata NULL 191 #define OMAP15XX_MCBSP_PDATA_SZ 0 192 #endif 193 194 #ifdef CONFIG_ARCH_OMAP16XX 195 static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = { 196 { 197 .phys_base = OMAP1610_MCBSP1_BASE, 198 .dma_rx_sync = OMAP_DMA_MCBSP1_RX, 199 .dma_tx_sync = OMAP_DMA_MCBSP1_TX, 200 .rx_irq = INT_McBSP1RX, 201 .tx_irq = INT_McBSP1TX, 202 .ops = &omap1_mcbsp_ops, 203 .clk_name = "mcbsp_clk", 204 }, 205 { 206 .phys_base = OMAP1610_MCBSP2_BASE, 207 .dma_rx_sync = OMAP_DMA_MCBSP2_RX, 208 .dma_tx_sync = OMAP_DMA_MCBSP2_TX, 209 .rx_irq = INT_1610_McBSP2_RX, 210 .tx_irq = INT_1610_McBSP2_TX, 211 .ops = &omap1_mcbsp_ops, 212 }, 213 { 214 .phys_base = OMAP1610_MCBSP3_BASE, 215 .dma_rx_sync = OMAP_DMA_MCBSP3_RX, 216 .dma_tx_sync = OMAP_DMA_MCBSP3_TX, 217 .rx_irq = INT_McBSP3RX, 218 .tx_irq = INT_McBSP3TX, 219 .ops = &omap1_mcbsp_ops, 220 .clk_name = "mcbsp_clk", 221 }, 222 }; 223 #define OMAP16XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap16xx_mcbsp_pdata) 224 #else 225 #define omap16xx_mcbsp_pdata NULL 226 #define OMAP16XX_MCBSP_PDATA_SZ 0 227 #endif 228 229 int __init omap1_mcbsp_init(void) 230 { 231 int i; 232 233 for (i = 0; i < omap_mcbsp_clks_size; i++) { 234 if (cpu_is_omap15xx() || cpu_is_omap16xx()) { 235 omap_mcbsp_clk_init(&omap_mcbsp_clks[i]); 236 clk_register(&omap_mcbsp_clks[i].clk); 237 } 238 } 239 240 if (cpu_is_omap730()) 241 omap_mcbsp_count = OMAP730_MCBSP_PDATA_SZ; 242 if (cpu_is_omap15xx()) 243 omap_mcbsp_count = OMAP15XX_MCBSP_PDATA_SZ; 244 if (cpu_is_omap16xx()) 245 omap_mcbsp_count = OMAP16XX_MCBSP_PDATA_SZ; 246 247 mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *), 248 GFP_KERNEL); 249 if (!mcbsp_ptr) 250 return -ENOMEM; 251 252 if (cpu_is_omap730()) 253 omap_mcbsp_register_board_cfg(omap730_mcbsp_pdata, 254 OMAP730_MCBSP_PDATA_SZ); 255 256 if (cpu_is_omap15xx()) 257 omap_mcbsp_register_board_cfg(omap15xx_mcbsp_pdata, 258 OMAP15XX_MCBSP_PDATA_SZ); 259 260 if (cpu_is_omap16xx()) 261 omap_mcbsp_register_board_cfg(omap16xx_mcbsp_pdata, 262 OMAP16XX_MCBSP_PDATA_SZ); 263 264 return omap_mcbsp_init(); 265 } 266 267 arch_initcall(omap1_mcbsp_init); 268