diff options
Diffstat (limited to 'sound/soc/fsl/p1022_ds.c')
-rw-r--r-- | sound/soc/fsl/p1022_ds.c | 158 |
1 files changed, 9 insertions, 149 deletions
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 982a1c944983..50adf4032bcc 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c | |||
@@ -14,12 +14,12 @@ | |||
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/of_device.h> | 15 | #include <linux/of_device.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/of_i2c.h> | ||
18 | #include <sound/soc.h> | 17 | #include <sound/soc.h> |
19 | #include <asm/fsl_guts.h> | 18 | #include <asm/fsl_guts.h> |
20 | 19 | ||
21 | #include "fsl_dma.h" | 20 | #include "fsl_dma.h" |
22 | #include "fsl_ssi.h" | 21 | #include "fsl_ssi.h" |
22 | #include "fsl_utils.h" | ||
23 | 23 | ||
24 | /* P1022-specific PMUXCR and DMUXCR bit definitions */ | 24 | /* P1022-specific PMUXCR and DMUXCR bit definitions */ |
25 | 25 | ||
@@ -57,8 +57,6 @@ static inline void guts_set_dmuxcr(struct ccsr_guts __iomem *guts, | |||
57 | /* There's only one global utilities register */ | 57 | /* There's only one global utilities register */ |
58 | static phys_addr_t guts_phys; | 58 | static phys_addr_t guts_phys; |
59 | 59 | ||
60 | #define DAI_NAME_SIZE 32 | ||
61 | |||
62 | /** | 60 | /** |
63 | * machine_data: machine-specific ASoC device data | 61 | * machine_data: machine-specific ASoC device data |
64 | * | 62 | * |
@@ -75,7 +73,6 @@ struct machine_data { | |||
75 | unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */ | 73 | unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */ |
76 | unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */ | 74 | unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */ |
77 | unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/ | 75 | unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/ |
78 | char codec_name[DAI_NAME_SIZE]; | ||
79 | char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ | 76 | char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ |
80 | }; | 77 | }; |
81 | 78 | ||
@@ -191,136 +188,6 @@ static struct snd_soc_ops p1022_ds_ops = { | |||
191 | }; | 188 | }; |
192 | 189 | ||
193 | /** | 190 | /** |
194 | * get_node_by_phandle_name - get a node by its phandle name | ||
195 | * | ||
196 | * This function takes a node, the name of a property in that node, and a | ||
197 | * compatible string. Assuming the property is a phandle to another node, | ||
198 | * it returns that node, (optionally) if that node is compatible. | ||
199 | * | ||
200 | * If the property is not a phandle, or the node it points to is not compatible | ||
201 | * with the specific string, then NULL is returned. | ||
202 | */ | ||
203 | static struct device_node *get_node_by_phandle_name(struct device_node *np, | ||
204 | const char *name, const char *compatible) | ||
205 | { | ||
206 | np = of_parse_phandle(np, name, 0); | ||
207 | if (!np) | ||
208 | return NULL; | ||
209 | |||
210 | if (!of_device_is_compatible(np, compatible)) { | ||
211 | of_node_put(np); | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | return np; | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * get_parent_cell_index -- return the cell-index of the parent of a node | ||
220 | * | ||
221 | * Return the value of the cell-index property of the parent of the given | ||
222 | * node. This is used for DMA channel nodes that need to know the DMA ID | ||
223 | * of the controller they are on. | ||
224 | */ | ||
225 | static int get_parent_cell_index(struct device_node *np) | ||
226 | { | ||
227 | struct device_node *parent = of_get_parent(np); | ||
228 | const u32 *iprop; | ||
229 | int ret = -1; | ||
230 | |||
231 | if (!parent) | ||
232 | return -1; | ||
233 | |||
234 | iprop = of_get_property(parent, "cell-index", NULL); | ||
235 | if (iprop) | ||
236 | ret = be32_to_cpup(iprop); | ||
237 | |||
238 | of_node_put(parent); | ||
239 | |||
240 | return ret; | ||
241 | } | ||
242 | |||
243 | /** | ||
244 | * codec_node_dev_name - determine the dev_name for a codec node | ||
245 | * | ||
246 | * This function determines the dev_name for an I2C node. This is the name | ||
247 | * that would be returned by dev_name() if this device_node were part of a | ||
248 | * 'struct device' It's ugly and hackish, but it works. | ||
249 | * | ||
250 | * The dev_name for such devices include the bus number and I2C address. For | ||
251 | * example, "cs4270-codec.0-004f". | ||
252 | */ | ||
253 | static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) | ||
254 | { | ||
255 | const u32 *iprop; | ||
256 | int addr; | ||
257 | char temp[DAI_NAME_SIZE]; | ||
258 | struct i2c_client *i2c; | ||
259 | |||
260 | of_modalias_node(np, temp, DAI_NAME_SIZE); | ||
261 | |||
262 | iprop = of_get_property(np, "reg", NULL); | ||
263 | if (!iprop) | ||
264 | return -EINVAL; | ||
265 | |||
266 | addr = be32_to_cpup(iprop); | ||
267 | |||
268 | /* We need the adapter number */ | ||
269 | i2c = of_find_i2c_device_by_node(np); | ||
270 | if (!i2c) | ||
271 | return -ENODEV; | ||
272 | |||
273 | snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int get_dma_channel(struct device_node *ssi_np, | ||
279 | const char *name, | ||
280 | struct snd_soc_dai_link *dai, | ||
281 | unsigned int *dma_channel_id, | ||
282 | unsigned int *dma_id) | ||
283 | { | ||
284 | struct resource res; | ||
285 | struct device_node *dma_channel_np; | ||
286 | const u32 *iprop; | ||
287 | int ret; | ||
288 | |||
289 | dma_channel_np = get_node_by_phandle_name(ssi_np, name, | ||
290 | "fsl,ssi-dma-channel"); | ||
291 | if (!dma_channel_np) | ||
292 | return -EINVAL; | ||
293 | |||
294 | /* Determine the dev_name for the device_node. This code mimics the | ||
295 | * behavior of of_device_make_bus_id(). We need this because ASoC uses | ||
296 | * the dev_name() of the device to match the platform (DMA) device with | ||
297 | * the CPU (SSI) device. It's all ugly and hackish, but it works (for | ||
298 | * now). | ||
299 | * | ||
300 | * dai->platform name should already point to an allocated buffer. | ||
301 | */ | ||
302 | ret = of_address_to_resource(dma_channel_np, 0, &res); | ||
303 | if (ret) { | ||
304 | of_node_put(dma_channel_np); | ||
305 | return ret; | ||
306 | } | ||
307 | snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s", | ||
308 | (unsigned long long) res.start, dma_channel_np->name); | ||
309 | |||
310 | iprop = of_get_property(dma_channel_np, "cell-index", NULL); | ||
311 | if (!iprop) { | ||
312 | of_node_put(dma_channel_np); | ||
313 | return -EINVAL; | ||
314 | } | ||
315 | |||
316 | *dma_channel_id = be32_to_cpup(iprop); | ||
317 | *dma_id = get_parent_cell_index(dma_channel_np); | ||
318 | of_node_put(dma_channel_np); | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | /** | ||
324 | * p1022_ds_probe: platform probe function for the machine driver | 191 | * p1022_ds_probe: platform probe function for the machine driver |
325 | * | 192 | * |
326 | * Although this is a machine driver, the SSI node is the "master" node with | 193 | * Although this is a machine driver, the SSI node is the "master" node with |
@@ -357,15 +224,8 @@ static int p1022_ds_probe(struct platform_device *pdev) | |||
357 | mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev); | 224 | mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev); |
358 | mdata->dai[0].ops = &p1022_ds_ops; | 225 | mdata->dai[0].ops = &p1022_ds_ops; |
359 | 226 | ||
360 | /* Determine the codec name, it will be used as the codec DAI name */ | 227 | /* ASoC core can match codec with device node */ |
361 | ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE); | 228 | mdata->dai[0].codec_of_node = codec_np; |
362 | if (ret) { | ||
363 | dev_err(&pdev->dev, "invalid codec node %s\n", | ||
364 | codec_np->full_name); | ||
365 | ret = -EINVAL; | ||
366 | goto error; | ||
367 | } | ||
368 | mdata->dai[0].codec_name = mdata->codec_name; | ||
369 | 229 | ||
370 | /* We register two DAIs per SSI, one for playback and the other for | 230 | /* We register two DAIs per SSI, one for playback and the other for |
371 | * capture. We support codecs that have separate DAIs for both playback | 231 | * capture. We support codecs that have separate DAIs for both playback |
@@ -462,9 +322,9 @@ static int p1022_ds_probe(struct platform_device *pdev) | |||
462 | 322 | ||
463 | /* Find the playback DMA channel to use. */ | 323 | /* Find the playback DMA channel to use. */ |
464 | mdata->dai[0].platform_name = mdata->platform_name[0]; | 324 | mdata->dai[0].platform_name = mdata->platform_name[0]; |
465 | ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0], | 325 | ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0], |
466 | &mdata->dma_channel_id[0], | 326 | &mdata->dma_channel_id[0], |
467 | &mdata->dma_id[0]); | 327 | &mdata->dma_id[0]); |
468 | if (ret) { | 328 | if (ret) { |
469 | dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n"); | 329 | dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n"); |
470 | goto error; | 330 | goto error; |
@@ -472,9 +332,9 @@ static int p1022_ds_probe(struct platform_device *pdev) | |||
472 | 332 | ||
473 | /* Find the capture DMA channel to use. */ | 333 | /* Find the capture DMA channel to use. */ |
474 | mdata->dai[1].platform_name = mdata->platform_name[1]; | 334 | mdata->dai[1].platform_name = mdata->platform_name[1]; |
475 | ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1], | 335 | ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1], |
476 | &mdata->dma_channel_id[1], | 336 | &mdata->dma_channel_id[1], |
477 | &mdata->dma_id[1]); | 337 | &mdata->dma_id[1]); |
478 | if (ret) { | 338 | if (ret) { |
479 | dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n"); | 339 | dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n"); |
480 | goto error; | 340 | goto error; |