Commit | Line | Data |
---|---|---|
c0af14d3 OL |
1 | /* |
2 | * Copyright (C) ST-Ericsson SA 2010 | |
3 | * | |
4 | * License terms: GNU General Public License (GPL), version 2 | |
5 | */ | |
6 | ||
7 | #include <linux/platform_device.h> | |
8 | #include <linux/init.h> | |
9 | #include <linux/gpio.h> | |
08d98fe0 | 10 | #include <linux/pinctrl/consumer.h> |
c0af14d3 | 11 | |
08d98fe0 | 12 | #include <plat/gpio-nomadik.h> |
c0af14d3 OL |
13 | #include <plat/pincfg.h> |
14 | #include <plat/ste_dma40.h> | |
15 | ||
16 | #include <mach/devices.h> | |
c0af14d3 OL |
17 | #include <mach/hardware.h> |
18 | #include <mach/irqs.h> | |
19 | #include <mach/msp.h> | |
20 | ||
08d98fe0 | 21 | #include "ste-dma40-db8500.h" |
c0af14d3 OL |
22 | #include "board-mop500.h" |
23 | #include "devices-db8500.h" | |
24 | #include "pins-db8500.h" | |
25 | ||
26 | /* MSP1/3 Tx/Rx usage protection */ | |
27 | static DEFINE_SPINLOCK(msp_rxtx_lock); | |
28 | ||
29 | /* Reference Count */ | |
30 | static int msp_rxtx_ref; | |
31 | ||
08d98fe0 LW |
32 | /* Pin modes */ |
33 | struct pinctrl *msp1_p; | |
34 | struct pinctrl_state *msp1_def; | |
35 | struct pinctrl_state *msp1_sleep; | |
c0af14d3 OL |
36 | |
37 | int msp13_i2s_init(void) | |
38 | { | |
39 | int retval = 0; | |
40 | unsigned long flags; | |
41 | ||
42 | spin_lock_irqsave(&msp_rxtx_lock, flags); | |
08d98fe0 LW |
43 | if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_def))) { |
44 | retval = pinctrl_select_state(msp1_p, msp1_def); | |
45 | if (retval) | |
46 | pr_err("could not set MSP1 defstate\n"); | |
47 | } | |
c0af14d3 OL |
48 | if (!retval) |
49 | msp_rxtx_ref++; | |
50 | spin_unlock_irqrestore(&msp_rxtx_lock, flags); | |
51 | ||
52 | return retval; | |
53 | } | |
54 | ||
55 | int msp13_i2s_exit(void) | |
56 | { | |
57 | int retval = 0; | |
58 | unsigned long flags; | |
59 | ||
60 | spin_lock_irqsave(&msp_rxtx_lock, flags); | |
61 | WARN_ON(!msp_rxtx_ref); | |
62 | msp_rxtx_ref--; | |
08d98fe0 LW |
63 | if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_sleep))) { |
64 | retval = pinctrl_select_state(msp1_p, msp1_sleep); | |
65 | if (retval) | |
66 | pr_err("could not set MSP1 sleepstate\n"); | |
67 | } | |
c0af14d3 OL |
68 | spin_unlock_irqrestore(&msp_rxtx_lock, flags); |
69 | ||
70 | return retval; | |
71 | } | |
72 | ||
73 | static struct stedma40_chan_cfg msp0_dma_rx = { | |
74 | .high_priority = true, | |
75 | .dir = STEDMA40_PERIPH_TO_MEM, | |
76 | ||
77 | .src_dev_type = DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX, | |
78 | .dst_dev_type = STEDMA40_DEV_DST_MEMORY, | |
79 | ||
80 | .src_info.psize = STEDMA40_PSIZE_LOG_4, | |
81 | .dst_info.psize = STEDMA40_PSIZE_LOG_4, | |
82 | ||
83 | /* data_width is set during configuration */ | |
84 | }; | |
85 | ||
86 | static struct stedma40_chan_cfg msp0_dma_tx = { | |
87 | .high_priority = true, | |
88 | .dir = STEDMA40_MEM_TO_PERIPH, | |
89 | ||
90 | .src_dev_type = STEDMA40_DEV_DST_MEMORY, | |
91 | .dst_dev_type = DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX, | |
92 | ||
93 | .src_info.psize = STEDMA40_PSIZE_LOG_4, | |
94 | .dst_info.psize = STEDMA40_PSIZE_LOG_4, | |
95 | ||
96 | /* data_width is set during configuration */ | |
97 | }; | |
98 | ||
99 | static struct msp_i2s_platform_data msp0_platform_data = { | |
100 | .id = MSP_I2S_0, | |
101 | .msp_i2s_dma_rx = &msp0_dma_rx, | |
102 | .msp_i2s_dma_tx = &msp0_dma_tx, | |
103 | }; | |
104 | ||
105 | static struct stedma40_chan_cfg msp1_dma_rx = { | |
106 | .high_priority = true, | |
107 | .dir = STEDMA40_PERIPH_TO_MEM, | |
108 | ||
109 | .src_dev_type = DB8500_DMA_DEV30_MSP3_RX, | |
110 | .dst_dev_type = STEDMA40_DEV_DST_MEMORY, | |
111 | ||
112 | .src_info.psize = STEDMA40_PSIZE_LOG_4, | |
113 | .dst_info.psize = STEDMA40_PSIZE_LOG_4, | |
114 | ||
115 | /* data_width is set during configuration */ | |
116 | }; | |
117 | ||
118 | static struct stedma40_chan_cfg msp1_dma_tx = { | |
119 | .high_priority = true, | |
120 | .dir = STEDMA40_MEM_TO_PERIPH, | |
121 | ||
122 | .src_dev_type = STEDMA40_DEV_DST_MEMORY, | |
123 | .dst_dev_type = DB8500_DMA_DEV30_MSP1_TX, | |
124 | ||
125 | .src_info.psize = STEDMA40_PSIZE_LOG_4, | |
126 | .dst_info.psize = STEDMA40_PSIZE_LOG_4, | |
127 | ||
128 | /* data_width is set during configuration */ | |
129 | }; | |
130 | ||
131 | static struct msp_i2s_platform_data msp1_platform_data = { | |
132 | .id = MSP_I2S_1, | |
133 | .msp_i2s_dma_rx = NULL, | |
134 | .msp_i2s_dma_tx = &msp1_dma_tx, | |
135 | .msp_i2s_init = msp13_i2s_init, | |
136 | .msp_i2s_exit = msp13_i2s_exit, | |
137 | }; | |
138 | ||
139 | static struct stedma40_chan_cfg msp2_dma_rx = { | |
140 | .high_priority = true, | |
141 | .dir = STEDMA40_PERIPH_TO_MEM, | |
142 | ||
143 | .src_dev_type = DB8500_DMA_DEV14_MSP2_RX, | |
144 | .dst_dev_type = STEDMA40_DEV_DST_MEMORY, | |
145 | ||
146 | /* MSP2 DMA doesn't work with PSIZE == 4 on DB8500v2 */ | |
147 | .src_info.psize = STEDMA40_PSIZE_LOG_1, | |
148 | .dst_info.psize = STEDMA40_PSIZE_LOG_1, | |
149 | ||
150 | /* data_width is set during configuration */ | |
151 | }; | |
152 | ||
153 | static struct stedma40_chan_cfg msp2_dma_tx = { | |
154 | .high_priority = true, | |
155 | .dir = STEDMA40_MEM_TO_PERIPH, | |
156 | ||
157 | .src_dev_type = STEDMA40_DEV_DST_MEMORY, | |
158 | .dst_dev_type = DB8500_DMA_DEV14_MSP2_TX, | |
159 | ||
160 | .src_info.psize = STEDMA40_PSIZE_LOG_4, | |
161 | .dst_info.psize = STEDMA40_PSIZE_LOG_4, | |
162 | ||
163 | .use_fixed_channel = true, | |
164 | .phy_channel = 1, | |
165 | ||
166 | /* data_width is set during configuration */ | |
167 | }; | |
168 | ||
09486cbb LW |
169 | static struct platform_device *db8500_add_msp_i2s(struct device *parent, |
170 | int id, | |
c0af14d3 OL |
171 | resource_size_t base, int irq, |
172 | struct msp_i2s_platform_data *pdata) | |
173 | { | |
174 | struct platform_device *pdev; | |
175 | struct resource res[] = { | |
176 | DEFINE_RES_MEM(base, SZ_4K), | |
177 | DEFINE_RES_IRQ(irq), | |
178 | }; | |
179 | ||
180 | pr_info("Register platform-device 'ux500-msp-i2s', id %d, irq %d\n", | |
181 | id, irq); | |
182 | pdev = platform_device_register_resndata(parent, "ux500-msp-i2s", id, | |
183 | res, ARRAY_SIZE(res), | |
184 | pdata, sizeof(*pdata)); | |
185 | if (!pdev) { | |
186 | pr_err("Failed to register platform-device 'ux500-msp-i2s.%d'!\n", | |
187 | id); | |
09486cbb | 188 | return NULL; |
c0af14d3 OL |
189 | } |
190 | ||
09486cbb | 191 | return pdev; |
c0af14d3 OL |
192 | } |
193 | ||
97f50c6c LJ |
194 | /* Platform device for ASoC MOP500 machine */ |
195 | static struct platform_device snd_soc_mop500 = { | |
196 | .name = "snd-soc-mop500", | |
c0af14d3 OL |
197 | .id = 0, |
198 | .dev = { | |
199 | .platform_data = NULL, | |
200 | }, | |
201 | }; | |
202 | ||
203 | /* Platform device for Ux500-PCM */ | |
204 | static struct platform_device ux500_pcm = { | |
205 | .name = "ux500-pcm", | |
206 | .id = 0, | |
207 | .dev = { | |
208 | .platform_data = NULL, | |
209 | }, | |
210 | }; | |
211 | ||
212 | static struct msp_i2s_platform_data msp2_platform_data = { | |
213 | .id = MSP_I2S_2, | |
214 | .msp_i2s_dma_rx = &msp2_dma_rx, | |
215 | .msp_i2s_dma_tx = &msp2_dma_tx, | |
216 | }; | |
217 | ||
218 | static struct msp_i2s_platform_data msp3_platform_data = { | |
219 | .id = MSP_I2S_3, | |
220 | .msp_i2s_dma_rx = &msp1_dma_rx, | |
221 | .msp_i2s_dma_tx = NULL, | |
222 | .msp_i2s_init = msp13_i2s_init, | |
223 | .msp_i2s_exit = msp13_i2s_exit, | |
224 | }; | |
225 | ||
226 | int mop500_msp_init(struct device *parent) | |
227 | { | |
08d98fe0 LW |
228 | struct platform_device *msp1; |
229 | ||
97f50c6c LJ |
230 | pr_info("%s: Register platform-device 'snd-soc-mop500'.\n", __func__); |
231 | platform_device_register(&snd_soc_mop500); | |
c0af14d3 OL |
232 | |
233 | pr_info("Initialize MSP I2S-devices.\n"); | |
09486cbb LW |
234 | db8500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, |
235 | &msp0_platform_data); | |
08d98fe0 | 236 | msp1 = db8500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, |
09486cbb LW |
237 | &msp1_platform_data); |
238 | db8500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, | |
239 | &msp2_platform_data); | |
240 | db8500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, | |
241 | &msp3_platform_data); | |
c0af14d3 | 242 | |
08d98fe0 LW |
243 | /* Get the pinctrl handle for MSP1 */ |
244 | if (msp1) { | |
245 | msp1_p = pinctrl_get(&msp1->dev); | |
246 | if (IS_ERR(msp1_p)) | |
247 | dev_err(&msp1->dev, "could not get MSP1 pinctrl\n"); | |
248 | else { | |
249 | msp1_def = pinctrl_lookup_state(msp1_p, | |
250 | PINCTRL_STATE_DEFAULT); | |
251 | if (IS_ERR(msp1_def)) { | |
252 | dev_err(&msp1->dev, | |
253 | "could not get MSP1 defstate\n"); | |
254 | } | |
255 | msp1_sleep = pinctrl_lookup_state(msp1_p, | |
256 | PINCTRL_STATE_SLEEP); | |
257 | if (IS_ERR(msp1_sleep)) | |
258 | dev_err(&msp1->dev, | |
259 | "could not get MSP1 idlestate\n"); | |
260 | } | |
261 | } | |
262 | ||
c0af14d3 OL |
263 | pr_info("%s: Register platform-device 'ux500-pcm'\n", __func__); |
264 | platform_device_register(&ux500_pcm); | |
265 | ||
09486cbb | 266 | return 0; |
c0af14d3 | 267 | } |