blob: aef5ceeb573fcf12fe141831b9b13c2dac5746fb [file] [log] [blame]
Liam Girdwood9a8c9c22011-02-03 18:25:55 +00001/*
2 * ALSA SoC OMAP ABE port manager
3 *
4 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 */
20
21//#define DEBUG
22
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/errno.h>
27#include <linux/spinlock.h>
28#include <linux/list.h>
29#include <linux/debugfs.h>
30#include <linux/device.h>
31#include "port_mgr.h"
32#include "abe_main.h"
33
Liam Girdwood9a8c9c22011-02-03 18:25:55 +000034/* this must match logical ID numbers in port_mgr.h */
35static const char *lport_name[] = {
36 "dmic0", "dmic1", "dmic2", "pdmdl1", "pdmdl2", "pdmvib",
37 "pdmul1", "bt_vx_dl", "bt_vx_ul", "mm_ext_ul", "mm_ext_dl",
38 "mm_dl1", "mm_ul1", "mm_ul2", "vx_dl", "vx_ul", "vib", "tones"
39};
Liam Girdwood9a8c9c22011-02-03 18:25:55 +000040
41static DEFINE_MUTEX(port_mgr_mutex);
42static struct abe *the_abe = NULL;
43static int users = 0;
44
45/*
46 * Get the Physical port ID based on the logical port ID
47 *
48 * FE and BE ports have unique ID's within the driver but share
49 * ID's within the ABE. This maps a driver port ID to an ABE port ID.
50 */
51static int get_physical_id(int logical_id)
52{
53 switch (logical_id) {
54 /* backend ports */
55 case OMAP_ABE_BE_PORT_DMIC0:
56 case OMAP_ABE_BE_PORT_DMIC1:
57 case OMAP_ABE_BE_PORT_DMIC2:
58 return DMIC_PORT;
59 case OMAP_ABE_BE_PORT_PDM_DL1:
60 case OMAP_ABE_BE_PORT_PDM_DL2:
61 return PDM_DL_PORT;
62 case OMAP_ABE_BE_PORT_PDM_VIB:
63 return VIB_DL_PORT;
64 case OMAP_ABE_BE_PORT_PDM_UL1:
65 return PDM_UL_PORT;
66 case OMAP_ABE_BE_PORT_BT_VX_DL:
67 return BT_VX_DL_PORT;
68 case OMAP_ABE_BE_PORT_BT_VX_UL:
69 return BT_VX_UL_PORT;
70 case OMAP_ABE_BE_PORT_MM_EXT_UL:
71 return MM_EXT_OUT_PORT;
72 case OMAP_ABE_BE_PORT_MM_EXT_DL:
73 return MM_EXT_IN_PORT;
74 /* front end ports */
75 case OMAP_ABE_FE_PORT_MM_DL1:
76 return MM_DL_PORT;
77 case OMAP_ABE_FE_PORT_MM_UL1:
78 return MM_UL_PORT;
79 case OMAP_ABE_FE_PORT_MM_UL2:
80 return MM_UL2_PORT;
81 case OMAP_ABE_FE_PORT_VX_DL:
82 return VX_DL_PORT;
83 case OMAP_ABE_FE_PORT_VX_UL:
84 return VX_UL_PORT;
85 case OMAP_ABE_FE_PORT_VIB:
86 return VIB_DL_PORT;
87 case OMAP_ABE_FE_PORT_TONES:
88 return TONES_DL_PORT;
89 }
90 return -EINVAL;
91}
92
93/*
94 * Get the number of enabled users of the physical port shared by this client.
95 * Locks held by callers.
96 */
97static int port_get_num_users(struct abe *abe, struct omap_abe_port *port)
98{
99 struct omap_abe_port *p;
100 int users = 0;
101
102 list_for_each_entry(p, &abe->ports, list) {
103 if (p->physical_id == port->physical_id && p->state == PORT_ENABLED)
104 users++;
105 }
106 return users;
107}
108
109static int port_is_open(struct abe *abe, int phy_port)
110{
111 struct omap_abe_port *p;
112
113 list_for_each_entry(p, &abe->ports, list) {
114 if (p->physical_id == phy_port && p->state == PORT_ENABLED)
115 return 1;
116 }
117 return 0;
118}
119
120/*
121 * Check whether the physical port is enabled for this PHY port ID.
122 * Locks held by callers.
123 */
124int omap_abe_port_is_enabled(struct abe *abe, struct omap_abe_port *port)
125{
126 struct omap_abe_port *p;
127 unsigned long flags;
128
129 spin_lock_irqsave(&abe->lock, flags);
130
131 list_for_each_entry(p, &abe->ports, list) {
132 if (p->physical_id == port->physical_id && p->state == PORT_ENABLED) {
133 spin_unlock_irqrestore(&abe->lock, flags);
134 return 1;
135 }
136 }
137
138 spin_unlock_irqrestore(&abe->lock, flags);
139 return 0;
140}
141EXPORT_SYMBOL(omap_abe_port_is_enabled);
142
143/*
144 * omap_abe_port_enable - enable ABE logical port
145 *
146 * @abe - ABE.
147 * @port - logical ABE port ID to be enabled.
148 */
149int omap_abe_port_enable(struct abe *abe, struct omap_abe_port *port)
150{
151 int ret = 0;
152 unsigned long flags;
153
154 /* only enable the physical port iff it is disabled */
155 pr_debug("port %s increment count %d\n",
156 lport_name[port->logical_id], port->users);
157
158 spin_lock_irqsave(&abe->lock, flags);
159 if (port->users == 0 && port_get_num_users(abe, port) == 0) {
160
161 /* enable the physical port */
162 pr_debug("port %s phy port %d enabled\n",
163 lport_name[port->logical_id], port->physical_id);
164 abe_enable_data_transfer(port->physical_id);
165 }
166
167 port->state = PORT_ENABLED;
168 port->users++;
169 spin_unlock_irqrestore(&abe->lock, flags);
170 return ret;
171}
172EXPORT_SYMBOL(omap_abe_port_enable);
173
174/*
175 * omap_abe_port_disable - disable ABE logical port
176 *
177 * @abe - ABE.
178 * @port - logical ABE port ID to be disabled.
179 */
180int omap_abe_port_disable(struct abe *abe, struct omap_abe_port *port)
181{
182 int ret = 0;
183 unsigned long flags;
184
185 /* only disable the port iff no other users are using it */
186 pr_debug("port %s decrement count %d\n",
187 lport_name[port->logical_id], port->users);
188
189 spin_lock_irqsave(&abe->lock, flags);
190 if (port->users == 1 && port_get_num_users(abe, port) == 1) {
191 /* disable the physical port */
192 pr_debug("port %s phy port %d disabled\n",
193 lport_name[port->logical_id], port->physical_id);
194
195 abe_disable_data_transfer(port->physical_id);
196 }
197
198 port->state = PORT_DISABLED;
199 port->users--;
200 spin_unlock_irqrestore(&abe->lock, flags);
201 return ret;
202}
203EXPORT_SYMBOL(omap_abe_port_disable);
204
205/*
206 * omap_abe_port_open - open ABE logical port
207 *
208 * @abe - ABE.
209 * @logical_id - logical ABE port ID to be opened.
210 */
211struct omap_abe_port *omap_abe_port_open(struct abe *abe, int logical_id)
212{
213 struct omap_abe_port *port;
214 unsigned long flags;
215
216#ifdef CONFIG_DEBUG_FS
217 char debug_fs_name[32];
218#endif
219
220 if (logical_id < 0 || logical_id > OMAP_ABE_MAX_PORT_ID)
221 return NULL;
222
223 if (port_is_open(abe, logical_id))
224 return NULL;
225
226 port = kzalloc(sizeof(struct omap_abe_port), GFP_KERNEL);
227 if (port == NULL)
228 return NULL;
229
230 port->logical_id = logical_id;
231 port->physical_id = get_physical_id(logical_id);
232 port->state = PORT_DISABLED;
233 port->abe = abe;
234
235 spin_lock_irqsave(&abe->lock, flags);
236 list_add(&port->list, &abe->ports);
237 spin_unlock_irqrestore(&abe->lock, flags);
238 port->physical_users = port_get_num_users(abe, port);
239
240#ifdef CONFIG_DEBUG_FS
241 sprintf(debug_fs_name, "%s_state", lport_name[logical_id]);
242 port->debugfs_lstate = debugfs_create_u32(debug_fs_name, 0644,
243 abe->debugfs_root, &port->state);
244 sprintf(debug_fs_name, "%s_phy", lport_name[logical_id]);
245 port->debugfs_lphy = debugfs_create_u32(debug_fs_name, 0644,
246 abe->debugfs_root, &port->physical_id);
247 sprintf(debug_fs_name, "%s_users", lport_name[logical_id]);
248 port->debugfs_lusers = debugfs_create_u32(debug_fs_name, 0644,
249 abe->debugfs_root, &port->users);
250#endif
251
252 pr_debug("opened port %s\n", lport_name[logical_id]);
253 return port;
254}
255EXPORT_SYMBOL(omap_abe_port_open);
256
257/*
258 * omap_abe_port_close - close ABE logical port
259 *
260 * @port - logical ABE port to be closed (and disabled).
261 */
262void omap_abe_port_close(struct abe *abe, struct omap_abe_port *port)
263{
264 unsigned long flags;
265
266 /* disable the port */
267 omap_abe_port_disable(abe, port);
268
269 spin_lock_irqsave(&abe->lock, flags);
270 list_del(&port->list);
271 spin_unlock_irqrestore(&abe->lock, flags);
272
273 pr_debug("closed port %s\n", lport_name[port->logical_id]);
274 kfree(port);
275}
276EXPORT_SYMBOL(omap_abe_port_close);
277
278static struct abe *omap_abe_port_mgr_init(void)
279{
280 struct abe *abe;
281
282 abe = kzalloc(sizeof(struct abe), GFP_KERNEL);
283 if (abe == NULL)
284 return NULL;
285
286 spin_lock_init(&abe->lock);
287
288 INIT_LIST_HEAD(&abe->ports);
289 the_abe = abe;
290
291#ifdef CONFIG_DEBUG_FS
292 abe->debugfs_root = debugfs_create_dir("abe_port", NULL);
293 if (!abe->debugfs_root) {
294 pr_debug( "Failed to create port manager debugfs directory\n");
295 }
296#endif
297 return abe;
298}
299
300static void omap_abe_port_mgr_free(struct abe *abe)
301{
Sebastien Guiriec26330ed2011-07-05 16:06:31 +0200302#ifdef CONFIG_DEBUG_FS
Liam Girdwood9a8c9c22011-02-03 18:25:55 +0000303 debugfs_remove_recursive(abe->debugfs_root);
Sebastien Guiriec26330ed2011-07-05 16:06:31 +0200304#endif
Liam Girdwood9a8c9c22011-02-03 18:25:55 +0000305 kfree(abe);
306 the_abe = NULL;
307}
308
309struct abe *omap_abe_port_mgr_get(void)
310{
311 struct abe * abe;
312
313 mutex_lock(&port_mgr_mutex);
314
315 if (the_abe)
316 abe = the_abe;
317 else
318 abe = omap_abe_port_mgr_init();
319
320 users++;
321 mutex_unlock(&port_mgr_mutex);
322 return abe;
323}
324EXPORT_SYMBOL(omap_abe_port_mgr_get);
325
326void omap_abe_port_mgr_put(struct abe *abe)
327{
328 mutex_lock(&port_mgr_mutex);
329
330 if (users == 0)
331 goto out;
332
333 if (--users == 0)
334 omap_abe_port_mgr_free(abe);
335
336out:
337 mutex_unlock(&port_mgr_mutex);
338}
339EXPORT_SYMBOL(omap_abe_port_mgr_put);
340
341MODULE_LICENSE("GPL");