diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2012-03-16 04:56:40 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-04-01 06:28:27 -0400 |
commit | 60aae8da298e3ac0af07c8cdb6a98e47e8deab35 (patch) | |
tree | 3d8b42210aaff89459c8a7ec7185a8c7e4ac616f /sound/soc/fsl/mpc8610_hpcd.c | |
parent | f19493a3d25ddf3ac7f27d846d54e95fb91af119 (diff) |
ASoC: fsl: create fsl_utils to accommodate the common functions
There is some amount of code duplication between mpc8610_hpcd and
p1022_ds machine drivers, and the same code will be duplicated again
when another new machine driver is added. The patch creates fsl_utils
to accommodate the common functions to stop the code duplication.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/fsl/mpc8610_hpcd.c')
-rw-r--r-- | sound/soc/fsl/mpc8610_hpcd.c | 157 |
1 files changed, 11 insertions, 146 deletions
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index afbabf427f27..41951820b50e 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
@@ -14,18 +14,16 @@ | |||
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 | /* There's only one global utilities register */ | 24 | /* There's only one global utilities register */ |
25 | static phys_addr_t guts_phys; | 25 | static phys_addr_t guts_phys; |
26 | 26 | ||
27 | #define DAI_NAME_SIZE 32 | ||
28 | |||
29 | /** | 27 | /** |
30 | * mpc8610_hpcd_data: machine-specific ASoC device data | 28 | * mpc8610_hpcd_data: machine-specific ASoC device data |
31 | * | 29 | * |
@@ -181,141 +179,6 @@ static struct snd_soc_ops mpc8610_hpcd_ops = { | |||
181 | }; | 179 | }; |
182 | 180 | ||
183 | /** | 181 | /** |
184 | * get_node_by_phandle_name - get a node by its phandle name | ||
185 | * | ||
186 | * This function takes a node, the name of a property in that node, and a | ||
187 | * compatible string. Assuming the property is a phandle to another node, | ||
188 | * it returns that node, (optionally) if that node is compatible. | ||
189 | * | ||
190 | * If the property is not a phandle, or the node it points to is not compatible | ||
191 | * with the specific string, then NULL is returned. | ||
192 | */ | ||
193 | static struct device_node *get_node_by_phandle_name(struct device_node *np, | ||
194 | const char *name, | ||
195 | const char *compatible) | ||
196 | { | ||
197 | const phandle *ph; | ||
198 | int len; | ||
199 | |||
200 | ph = of_get_property(np, name, &len); | ||
201 | if (!ph || (len != sizeof(phandle))) | ||
202 | return NULL; | ||
203 | |||
204 | np = of_find_node_by_phandle(*ph); | ||
205 | if (!np) | ||
206 | return NULL; | ||
207 | |||
208 | if (compatible && !of_device_is_compatible(np, compatible)) { | ||
209 | of_node_put(np); | ||
210 | return NULL; | ||
211 | } | ||
212 | |||
213 | return np; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * get_parent_cell_index -- return the cell-index of the parent of a node | ||
218 | * | ||
219 | * Return the value of the cell-index property of the parent of the given | ||
220 | * node. This is used for DMA channel nodes that need to know the DMA ID | ||
221 | * of the controller they are on. | ||
222 | */ | ||
223 | static int get_parent_cell_index(struct device_node *np) | ||
224 | { | ||
225 | struct device_node *parent = of_get_parent(np); | ||
226 | const u32 *iprop; | ||
227 | |||
228 | if (!parent) | ||
229 | return -1; | ||
230 | |||
231 | iprop = of_get_property(parent, "cell-index", NULL); | ||
232 | of_node_put(parent); | ||
233 | |||
234 | if (!iprop) | ||
235 | return -1; | ||
236 | |||
237 | return be32_to_cpup(iprop); | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * codec_node_dev_name - determine the dev_name for a codec node | ||
242 | * | ||
243 | * This function determines the dev_name for an I2C node. This is the name | ||
244 | * that would be returned by dev_name() if this device_node were part of a | ||
245 | * 'struct device' It's ugly and hackish, but it works. | ||
246 | * | ||
247 | * The dev_name for such devices include the bus number and I2C address. For | ||
248 | * example, "cs4270.0-004f". | ||
249 | */ | ||
250 | static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) | ||
251 | { | ||
252 | const u32 *iprop; | ||
253 | int addr; | ||
254 | char temp[DAI_NAME_SIZE]; | ||
255 | struct i2c_client *i2c; | ||
256 | |||
257 | of_modalias_node(np, temp, DAI_NAME_SIZE); | ||
258 | |||
259 | iprop = of_get_property(np, "reg", NULL); | ||
260 | if (!iprop) | ||
261 | return -EINVAL; | ||
262 | |||
263 | addr = be32_to_cpup(iprop); | ||
264 | |||
265 | /* We need the adapter number */ | ||
266 | i2c = of_find_i2c_device_by_node(np); | ||
267 | if (!i2c) | ||
268 | return -ENODEV; | ||
269 | |||
270 | snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int get_dma_channel(struct device_node *ssi_np, | ||
276 | const char *name, | ||
277 | struct snd_soc_dai_link *dai, | ||
278 | unsigned int *dma_channel_id, | ||
279 | unsigned int *dma_id) | ||
280 | { | ||
281 | struct resource res; | ||
282 | struct device_node *dma_channel_np; | ||
283 | const u32 *iprop; | ||
284 | int ret; | ||
285 | |||
286 | dma_channel_np = get_node_by_phandle_name(ssi_np, name, | ||
287 | "fsl,ssi-dma-channel"); | ||
288 | if (!dma_channel_np) | ||
289 | return -EINVAL; | ||
290 | |||
291 | /* Determine the dev_name for the device_node. This code mimics the | ||
292 | * behavior of of_device_make_bus_id(). We need this because ASoC uses | ||
293 | * the dev_name() of the device to match the platform (DMA) device with | ||
294 | * the CPU (SSI) device. It's all ugly and hackish, but it works (for | ||
295 | * now). | ||
296 | * | ||
297 | * dai->platform name should already point to an allocated buffer. | ||
298 | */ | ||
299 | ret = of_address_to_resource(dma_channel_np, 0, &res); | ||
300 | if (ret) | ||
301 | return ret; | ||
302 | snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s", | ||
303 | (unsigned long long) res.start, dma_channel_np->name); | ||
304 | |||
305 | iprop = of_get_property(dma_channel_np, "cell-index", NULL); | ||
306 | if (!iprop) { | ||
307 | of_node_put(dma_channel_np); | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | |||
311 | *dma_channel_id = be32_to_cpup(iprop); | ||
312 | *dma_id = get_parent_cell_index(dma_channel_np); | ||
313 | of_node_put(dma_channel_np); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * mpc8610_hpcd_probe: platform probe function for the machine driver | 182 | * mpc8610_hpcd_probe: platform probe function for the machine driver |
320 | * | 183 | * |
321 | * Although this is a machine driver, the SSI node is the "master" node with | 184 | * Although this is a machine driver, the SSI node is the "master" node with |
@@ -353,8 +216,8 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) | |||
353 | machine_data->dai[0].ops = &mpc8610_hpcd_ops; | 216 | machine_data->dai[0].ops = &mpc8610_hpcd_ops; |
354 | 217 | ||
355 | /* Determine the codec name, it will be used as the codec DAI name */ | 218 | /* Determine the codec name, it will be used as the codec DAI name */ |
356 | ret = codec_node_dev_name(codec_np, machine_data->codec_name, | 219 | ret = fsl_asoc_get_codec_dev_name(codec_np, machine_data->codec_name, |
357 | DAI_NAME_SIZE); | 220 | DAI_NAME_SIZE); |
358 | if (ret) { | 221 | if (ret) { |
359 | dev_err(&pdev->dev, "invalid codec node %s\n", | 222 | dev_err(&pdev->dev, "invalid codec node %s\n", |
360 | codec_np->full_name); | 223 | codec_np->full_name); |
@@ -458,9 +321,10 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) | |||
458 | 321 | ||
459 | /* Find the playback DMA channel to use. */ | 322 | /* Find the playback DMA channel to use. */ |
460 | machine_data->dai[0].platform_name = machine_data->platform_name[0]; | 323 | machine_data->dai[0].platform_name = machine_data->platform_name[0]; |
461 | ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0], | 324 | ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", |
462 | &machine_data->dma_channel_id[0], | 325 | &machine_data->dai[0], |
463 | &machine_data->dma_id[0]); | 326 | &machine_data->dma_channel_id[0], |
327 | &machine_data->dma_id[0]); | ||
464 | if (ret) { | 328 | if (ret) { |
465 | dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n"); | 329 | dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n"); |
466 | goto error; | 330 | goto error; |
@@ -468,9 +332,10 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) | |||
468 | 332 | ||
469 | /* Find the capture DMA channel to use. */ | 333 | /* Find the capture DMA channel to use. */ |
470 | machine_data->dai[1].platform_name = machine_data->platform_name[1]; | 334 | machine_data->dai[1].platform_name = machine_data->platform_name[1]; |
471 | ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1], | 335 | ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", |
472 | &machine_data->dma_channel_id[1], | 336 | &machine_data->dai[1], |
473 | &machine_data->dma_id[1]); | 337 | &machine_data->dma_channel_id[1], |
338 | &machine_data->dma_id[1]); | ||
474 | if (ret) { | 339 | if (ret) { |
475 | dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n"); | 340 | dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n"); |
476 | goto error; | 341 | goto error; |