| 1 | /* |
| 2 | * arch/ubicom32/mach-common/audio.c |
| 3 | * Generic initialization for Ubicom32 Audio |
| 4 | * |
| 5 | * (C) Copyright 2009, Ubicom, Inc. |
| 6 | * |
| 7 | * This file is part of the Ubicom32 Linux Kernel Port. |
| 8 | * |
| 9 | * The Ubicom32 Linux Kernel Port is free software: you can redistribute |
| 10 | * it and/or modify it under the terms of the GNU General Public License |
| 11 | * as published by the Free Software Foundation, either version 2 of the |
| 12 | * License, or (at your option) any later version. |
| 13 | * |
| 14 | * The Ubicom32 Linux Kernel Port is distributed in the hope that it |
| 15 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied |
| 16 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| 17 | * the GNU General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with the Ubicom32 Linux Kernel Port. If not, |
| 21 | * see <http://www.gnu.org/licenses/>. |
| 22 | */ |
| 23 | |
| 24 | #include <linux/platform_device.h> |
| 25 | #include <linux/types.h> |
| 26 | |
| 27 | #include <asm/devtree.h> |
| 28 | #include <asm/audio.h> |
| 29 | #include <asm/ubi32-pcm.h> |
| 30 | |
| 31 | /* |
| 32 | * The number of audio devices currently allocated, used for .id |
| 33 | */ |
| 34 | static int __initdata audio_device_count; |
| 35 | |
| 36 | /* |
| 37 | * The maximum number of resources (cards) that the audio will have. |
| 38 | * Currently 3, a register space, and up to 2 interrupts. |
| 39 | */ |
| 40 | #define AUDIO_MAX_RESOURCES 3 |
| 41 | |
| 42 | /* |
| 43 | * audio_device_alloc |
| 44 | * Checks the device tree and allocates a platform_device if found |
| 45 | */ |
| 46 | struct platform_device * __init audio_device_alloc(const char *driver_name, |
| 47 | const char *node_name, const char *inst_name, int priv_bytes) |
| 48 | { |
| 49 | struct platform_device *pdev; |
| 50 | struct resource *res; |
| 51 | struct audio_node *audio_node; |
| 52 | struct ubi32pcm_platform_data *pdata; |
| 53 | struct audio_dev_regs *adr; |
| 54 | int idx; |
| 55 | |
| 56 | /* |
| 57 | * Check the device tree for the audio node |
| 58 | */ |
| 59 | audio_node = (struct audio_node *)devtree_find_node(node_name); |
| 60 | if (!audio_node) { |
| 61 | printk(KERN_WARNING "audio device '%s' not found\n", node_name); |
| 62 | return NULL; |
| 63 | } |
| 64 | |
| 65 | if (audio_node->version != AUDIONODE_VERSION) { |
| 66 | printk(KERN_WARNING "audio node not compatible\n"); |
| 67 | return NULL; |
| 68 | } |
| 69 | |
| 70 | /* |
| 71 | * Find the instance in this node |
| 72 | */ |
| 73 | adr = audio_node->regs->adr; |
| 74 | for (idx = 0; idx < audio_node->regs->max_devs; idx++) { |
| 75 | if ((adr->version == AUDIO_DEV_REGS_VERSION) && |
| 76 | (strcmp(adr->name, inst_name) == 0)) { |
| 77 | break; |
| 78 | } |
| 79 | adr++; |
| 80 | } |
| 81 | if (idx == audio_node->regs->max_devs) { |
| 82 | printk(KERN_WARNING "audio inst '%s' not found in device '%s'\n", inst_name, node_name); |
| 83 | return NULL; |
| 84 | } |
| 85 | |
| 86 | /* |
| 87 | * Dynamically create the platform_device structure and resources |
| 88 | */ |
| 89 | pdev = kzalloc(sizeof(struct platform_device) + |
| 90 | sizeof(struct ubi32pcm_platform_data) + |
| 91 | priv_bytes , GFP_KERNEL); |
| 92 | if (!pdev) { |
| 93 | printk(KERN_WARNING "audio could not alloc pdev\n"); |
| 94 | return NULL; |
| 95 | } |
| 96 | |
| 97 | res = kzalloc(sizeof(struct resource) * AUDIO_MAX_RESOURCES, |
| 98 | GFP_KERNEL); |
| 99 | if (!res) { |
| 100 | kfree(pdev); |
| 101 | printk(KERN_WARNING "audio could not alloc res\n"); |
| 102 | return NULL; |
| 103 | } |
| 104 | |
| 105 | pdev->name = driver_name; |
| 106 | pdev->id = audio_device_count++; |
| 107 | pdev->resource = res; |
| 108 | |
| 109 | /* |
| 110 | * Fill in the resources and platform data from devtree information |
| 111 | */ |
| 112 | res[0].start = (u32_t)(audio_node->regs); |
| 113 | res[0].end = (u32_t)(audio_node->regs); |
| 114 | res[0].flags = IORESOURCE_MEM; |
| 115 | res[1 + AUDIO_TX_IRQ_RESOURCE].start = audio_node->dn.sendirq; |
| 116 | res[1 + AUDIO_TX_IRQ_RESOURCE].flags = IORESOURCE_IRQ; |
| 117 | res[1 + AUDIO_RX_IRQ_RESOURCE].start = audio_node->dn.recvirq; |
| 118 | res[1 + AUDIO_RX_IRQ_RESOURCE].flags = IORESOURCE_IRQ; |
| 119 | pdev->num_resources = 3; |
| 120 | |
| 121 | printk(KERN_INFO "Audio.%d '%s':'%s' found irq=%d/%d.%d regs=%p pdev=%p/%p\n", |
| 122 | pdev->id, node_name, inst_name, audio_node->dn.sendirq, |
| 123 | audio_node->dn.recvirq, idx, audio_node->regs, pdev, res); |
| 124 | pdata = (struct ubi32pcm_platform_data *)(pdev + 1); |
| 125 | pdev->dev.platform_data = pdata; |
| 126 | pdata->node_name = node_name; |
| 127 | pdata->inst_name = inst_name; |
| 128 | pdata->inst_num = idx; |
| 129 | if (priv_bytes) { |
| 130 | pdata->priv_data = pdata + 1; |
| 131 | } |
| 132 | |
| 133 | return pdev; |
| 134 | } |
| 135 | |