diff options
Diffstat (limited to 'arch/arm/mach-omap2/mcbsp.c')
-rw-r--r-- | arch/arm/mach-omap2/mcbsp.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c new file mode 100644 index 000000000000..17cf199d1130 --- /dev/null +++ b/arch/arm/mach-omap2/mcbsp.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap2/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 | |||
25 | struct mcbsp_internal_clk { | ||
26 | struct clk clk; | ||
27 | struct clk **childs; | ||
28 | int n_childs; | ||
29 | }; | ||
30 | |||
31 | #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) | ||
32 | static void omap_mcbsp_clk_init(struct mcbsp_internal_clk *mclk) | ||
33 | { | ||
34 | const char *clk_names[] = { "mcbsp_ick", "mcbsp_fck" }; | ||
35 | int i; | ||
36 | |||
37 | mclk->n_childs = ARRAY_SIZE(clk_names); | ||
38 | mclk->childs = kzalloc(mclk->n_childs * sizeof(struct clk *), | ||
39 | GFP_KERNEL); | ||
40 | |||
41 | for (i = 0; i < mclk->n_childs; i++) { | ||
42 | /* We fake a platform device to get correct device id */ | ||
43 | struct platform_device pdev; | ||
44 | |||
45 | pdev.dev.bus = &platform_bus_type; | ||
46 | pdev.id = mclk->clk.id; | ||
47 | mclk->childs[i] = clk_get(&pdev.dev, clk_names[i]); | ||
48 | if (IS_ERR(mclk->childs[i])) | ||
49 | printk(KERN_ERR "Could not get clock %s (%d).\n", | ||
50 | clk_names[i], mclk->clk.id); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | static int omap_mcbsp_clk_enable(struct clk *clk) | ||
55 | { | ||
56 | struct mcbsp_internal_clk *mclk = container_of(clk, | ||
57 | struct mcbsp_internal_clk, clk); | ||
58 | int i; | ||
59 | |||
60 | for (i = 0; i < mclk->n_childs; i++) | ||
61 | clk_enable(mclk->childs[i]); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static void omap_mcbsp_clk_disable(struct clk *clk) | ||
66 | { | ||
67 | struct mcbsp_internal_clk *mclk = container_of(clk, | ||
68 | struct mcbsp_internal_clk, clk); | ||
69 | int i; | ||
70 | |||
71 | for (i = 0; i < mclk->n_childs; i++) | ||
72 | clk_disable(mclk->childs[i]); | ||
73 | } | ||
74 | |||
75 | static struct mcbsp_internal_clk omap_mcbsp_clks[] = { | ||
76 | { | ||
77 | .clk = { | ||
78 | .name = "mcbsp_clk", | ||
79 | .id = 1, | ||
80 | .enable = omap_mcbsp_clk_enable, | ||
81 | .disable = omap_mcbsp_clk_disable, | ||
82 | }, | ||
83 | }, | ||
84 | { | ||
85 | .clk = { | ||
86 | .name = "mcbsp_clk", | ||
87 | .id = 2, | ||
88 | .enable = omap_mcbsp_clk_enable, | ||
89 | .disable = omap_mcbsp_clk_disable, | ||
90 | }, | ||
91 | }, | ||
92 | }; | ||
93 | |||
94 | #define omap_mcbsp_clks_size ARRAY_SIZE(omap_mcbsp_clks) | ||
95 | #else | ||
96 | #define omap_mcbsp_clks_size 0 | ||
97 | static struct mcbsp_internal_clk __initdata *omap_mcbsp_clks; | ||
98 | static inline void omap_mcbsp_clk_init(struct clk *clk) | ||
99 | { } | ||
100 | #endif | ||
101 | |||
102 | static void omap2_mcbsp2_mux_setup(void) | ||
103 | { | ||
104 | omap_cfg_reg(Y15_24XX_MCBSP2_CLKX); | ||
105 | omap_cfg_reg(R14_24XX_MCBSP2_FSX); | ||
106 | omap_cfg_reg(W15_24XX_MCBSP2_DR); | ||
107 | omap_cfg_reg(V15_24XX_MCBSP2_DX); | ||
108 | omap_cfg_reg(V14_24XX_GPIO117); | ||
109 | /* | ||
110 | * TODO: Need to add MUX settings for OMAP 2430 SDP | ||
111 | */ | ||
112 | } | ||
113 | |||
114 | static void omap2_mcbsp_request(unsigned int id) | ||
115 | { | ||
116 | if (cpu_is_omap2420() && (id == OMAP_MCBSP2)) | ||
117 | omap2_mcbsp2_mux_setup(); | ||
118 | } | ||
119 | |||
120 | static int omap2_mcbsp_check(unsigned int id) | ||
121 | { | ||
122 | if (id > OMAP_MAX_MCBSP_COUNT - 1) { | ||
123 | printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); | ||
124 | return -ENODEV; | ||
125 | } | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static struct omap_mcbsp_ops omap2_mcbsp_ops = { | ||
130 | .request = omap2_mcbsp_request, | ||
131 | .check = omap2_mcbsp_check, | ||
132 | }; | ||
133 | |||
134 | #ifdef CONFIG_ARCH_OMAP24XX | ||
135 | static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = { | ||
136 | { | ||
137 | .virt_base = IO_ADDRESS(OMAP24XX_MCBSP1_BASE), | ||
138 | .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX, | ||
139 | .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX, | ||
140 | .rx_irq = INT_24XX_MCBSP1_IRQ_RX, | ||
141 | .tx_irq = INT_24XX_MCBSP1_IRQ_TX, | ||
142 | .ops = &omap2_mcbsp_ops, | ||
143 | .clk_name = "mcbsp_clk", | ||
144 | }, | ||
145 | { | ||
146 | .virt_base = IO_ADDRESS(OMAP24XX_MCBSP2_BASE), | ||
147 | .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, | ||
148 | .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, | ||
149 | .rx_irq = INT_24XX_MCBSP2_IRQ_RX, | ||
150 | .tx_irq = INT_24XX_MCBSP2_IRQ_TX, | ||
151 | .ops = &omap2_mcbsp_ops, | ||
152 | .clk_name = "mcbsp_clk", | ||
153 | }, | ||
154 | }; | ||
155 | #define OMAP24XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap24xx_mcbsp_pdata) | ||
156 | #else | ||
157 | #define omap24xx_mcbsp_pdata NULL | ||
158 | #define OMAP24XX_MCBSP_PDATA_SZ 0 | ||
159 | #endif | ||
160 | |||
161 | #ifdef CONFIG_ARCH_OMAP34XX | ||
162 | static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { | ||
163 | { | ||
164 | .virt_base = IO_ADDRESS(OMAP34XX_MCBSP1_BASE), | ||
165 | .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX, | ||
166 | .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX, | ||
167 | .rx_irq = INT_24XX_MCBSP1_IRQ_RX, | ||
168 | .tx_irq = INT_24XX_MCBSP1_IRQ_TX, | ||
169 | .ops = &omap2_mcbsp_ops, | ||
170 | .clk_name = "mcbsp_clk", | ||
171 | }, | ||
172 | { | ||
173 | .virt_base = IO_ADDRESS(OMAP34XX_MCBSP2_BASE), | ||
174 | .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, | ||
175 | .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, | ||
176 | .rx_irq = INT_24XX_MCBSP2_IRQ_RX, | ||
177 | .tx_irq = INT_24XX_MCBSP2_IRQ_TX, | ||
178 | .ops = &omap2_mcbsp_ops, | ||
179 | .clk_name = "mcbsp_clk", | ||
180 | }, | ||
181 | }; | ||
182 | #define OMAP34XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap34xx_mcbsp_pdata) | ||
183 | #else | ||
184 | #define omap34xx_mcbsp_pdata NULL | ||
185 | #define OMAP34XX_MCBSP_PDATA_SZ 0 | ||
186 | #endif | ||
187 | |||
188 | int __init omap2_mcbsp_init(void) | ||
189 | { | ||
190 | int i; | ||
191 | |||
192 | for (i = 0; i < omap_mcbsp_clks_size; i++) { | ||
193 | /* Once we call clk_get inside init, we do not register it */ | ||
194 | omap_mcbsp_clk_init(&omap_mcbsp_clks[i]); | ||
195 | clk_register(&omap_mcbsp_clks[i].clk); | ||
196 | } | ||
197 | |||
198 | if (cpu_is_omap24xx()) | ||
199 | omap_mcbsp_register_board_cfg(omap24xx_mcbsp_pdata, | ||
200 | OMAP24XX_MCBSP_PDATA_SZ); | ||
201 | |||
202 | if (cpu_is_omap34xx()) | ||
203 | omap_mcbsp_register_board_cfg(omap34xx_mcbsp_pdata, | ||
204 | OMAP34XX_MCBSP_PDATA_SZ); | ||
205 | |||
206 | return omap_mcbsp_init(); | ||
207 | } | ||
208 | arch_initcall(omap2_mcbsp_init); | ||