xref: /linux/arch/arm/mach-omap2/mcbsp.c (revision e95496d4acadd0b72c4947be61e8d44700fdaae7)
178673bc8SEduardo Valentin /*
278673bc8SEduardo Valentin  * linux/arch/arm/mach-omap2/mcbsp.c
378673bc8SEduardo Valentin  *
478673bc8SEduardo Valentin  * Copyright (C) 2008 Instituto Nokia de Tecnologia
578673bc8SEduardo Valentin  * Contact: Eduardo Valentin <eduardo.valentin@indt.org.br>
678673bc8SEduardo Valentin  *
778673bc8SEduardo Valentin  * This program is free software; you can redistribute it and/or modify
878673bc8SEduardo Valentin  * it under the terms of the GNU General Public License version 2 as
978673bc8SEduardo Valentin  * published by the Free Software Foundation.
1078673bc8SEduardo Valentin  *
1178673bc8SEduardo Valentin  * Multichannel mode not supported.
1278673bc8SEduardo Valentin  */
1378673bc8SEduardo Valentin #include <linux/module.h>
1478673bc8SEduardo Valentin #include <linux/init.h>
1578673bc8SEduardo Valentin #include <linux/clk.h>
1678673bc8SEduardo Valentin #include <linux/err.h>
1778673bc8SEduardo Valentin #include <linux/io.h>
1878673bc8SEduardo Valentin #include <linux/platform_device.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
2078673bc8SEduardo Valentin 
21dd7667aaSTony Lindgren #include <mach/irqs.h>
22ce491cf8STony Lindgren #include <plat/dma.h>
23ce491cf8STony Lindgren #include <plat/cpu.h>
24ce491cf8STony Lindgren #include <plat/mcbsp.h>
2564bcbd33SKishon Vijay Abraham I #include <plat/omap_device.h>
26*e95496d4SKishon Vijay Abraham I #include <linux/pm_runtime.h>
274814ced5SPaul Walmsley 
284814ced5SPaul Walmsley #include "control.h"
294814ced5SPaul Walmsley 
30cf4c87abSPaul Walmsley /* McBSP internal signal muxing functions */
31cf4c87abSPaul Walmsley 
32cf4c87abSPaul Walmsley void omap2_mcbsp1_mux_clkr_src(u8 mux)
33cf4c87abSPaul Walmsley {
34cf4c87abSPaul Walmsley 	u32 v;
35cf4c87abSPaul Walmsley 
36cf4c87abSPaul Walmsley 	v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
37cf4c87abSPaul Walmsley 	if (mux == CLKR_SRC_CLKR)
38425925ddSJarkko Nikula 		v &= ~OMAP2_MCBSP1_CLKR_MASK;
39cf4c87abSPaul Walmsley 	else if (mux == CLKR_SRC_CLKX)
40cf4c87abSPaul Walmsley 		v |= OMAP2_MCBSP1_CLKR_MASK;
41cf4c87abSPaul Walmsley 	omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
42cf4c87abSPaul Walmsley }
43cf4c87abSPaul Walmsley EXPORT_SYMBOL(omap2_mcbsp1_mux_clkr_src);
44cf4c87abSPaul Walmsley 
45cf4c87abSPaul Walmsley void omap2_mcbsp1_mux_fsr_src(u8 mux)
46cf4c87abSPaul Walmsley {
47cf4c87abSPaul Walmsley 	u32 v;
48cf4c87abSPaul Walmsley 
49cf4c87abSPaul Walmsley 	v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
50cf4c87abSPaul Walmsley 	if (mux == FSR_SRC_FSR)
51425925ddSJarkko Nikula 		v &= ~OMAP2_MCBSP1_FSR_MASK;
52cf4c87abSPaul Walmsley 	else if (mux == FSR_SRC_FSX)
53cf4c87abSPaul Walmsley 		v |= OMAP2_MCBSP1_FSR_MASK;
54cf4c87abSPaul Walmsley 	omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
55cf4c87abSPaul Walmsley }
56cf4c87abSPaul Walmsley EXPORT_SYMBOL(omap2_mcbsp1_mux_fsr_src);
57cf4c87abSPaul Walmsley 
58d1358657SPaul Walmsley /* McBSP CLKS source switching function */
59d1358657SPaul Walmsley 
60d1358657SPaul Walmsley int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
61d1358657SPaul Walmsley {
62d1358657SPaul Walmsley 	struct omap_mcbsp *mcbsp;
63d1358657SPaul Walmsley 	struct clk *fck_src;
64d1358657SPaul Walmsley 	char *fck_src_name;
65d1358657SPaul Walmsley 	int r;
66d1358657SPaul Walmsley 
67d1358657SPaul Walmsley 	if (!omap_mcbsp_check_valid_id(id)) {
68d1358657SPaul Walmsley 		pr_err("%s: Invalid id (%d)\n", __func__, id + 1);
69d1358657SPaul Walmsley 		return -EINVAL;
70d1358657SPaul Walmsley 	}
71d1358657SPaul Walmsley 	mcbsp = id_to_mcbsp_ptr(id);
72d1358657SPaul Walmsley 
73d1358657SPaul Walmsley 	if (fck_src_id == MCBSP_CLKS_PAD_SRC)
74d1358657SPaul Walmsley 		fck_src_name = "pad_fck";
75d1358657SPaul Walmsley 	else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
76d1358657SPaul Walmsley 		fck_src_name = "prcm_fck";
77d1358657SPaul Walmsley 	else
78d1358657SPaul Walmsley 		return -EINVAL;
79d1358657SPaul Walmsley 
80d1358657SPaul Walmsley 	fck_src = clk_get(mcbsp->dev, fck_src_name);
81d1358657SPaul Walmsley 	if (IS_ERR_OR_NULL(fck_src)) {
82d1358657SPaul Walmsley 		pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks",
83d1358657SPaul Walmsley 		       fck_src_name);
84d1358657SPaul Walmsley 		return -EINVAL;
85d1358657SPaul Walmsley 	}
86d1358657SPaul Walmsley 
87*e95496d4SKishon Vijay Abraham I 	pm_runtime_put_sync(mcbsp->dev);
88d1358657SPaul Walmsley 
89d1358657SPaul Walmsley 	r = clk_set_parent(mcbsp->fclk, fck_src);
90d1358657SPaul Walmsley 	if (IS_ERR_VALUE(r)) {
91d1358657SPaul Walmsley 		pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n",
92d1358657SPaul Walmsley 		       "clks", fck_src_name);
93d1358657SPaul Walmsley 		clk_put(fck_src);
94d1358657SPaul Walmsley 		return -EINVAL;
95d1358657SPaul Walmsley 	}
96d1358657SPaul Walmsley 
97*e95496d4SKishon Vijay Abraham I 	pm_runtime_get_sync(mcbsp->dev);
98d1358657SPaul Walmsley 
99d1358657SPaul Walmsley 	clk_put(fck_src);
100d1358657SPaul Walmsley 
101d1358657SPaul Walmsley 	return 0;
102d1358657SPaul Walmsley }
103d1358657SPaul Walmsley EXPORT_SYMBOL(omap2_mcbsp_set_clks_src);
104d1358657SPaul Walmsley 
10564bcbd33SKishon Vijay Abraham I struct omap_device_pm_latency omap2_mcbsp_latency[] = {
10678673bc8SEduardo Valentin 	{
10764bcbd33SKishon Vijay Abraham I 		.deactivate_func = omap_device_idle_hwmods,
10864bcbd33SKishon Vijay Abraham I 		.activate_func   = omap_device_enable_hwmods,
10964bcbd33SKishon Vijay Abraham I 		.flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
1103cf32bbaSKishon Vijay Abraham I 	},
1113cf32bbaSKishon Vijay Abraham I };
1123cf32bbaSKishon Vijay Abraham I 
11364bcbd33SKishon Vijay Abraham I static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
11478673bc8SEduardo Valentin {
11564bcbd33SKishon Vijay Abraham I 	int id, count = 1;
11664bcbd33SKishon Vijay Abraham I 	char *name = "omap-mcbsp";
11764bcbd33SKishon Vijay Abraham I 	struct omap_hwmod *oh_device[2];
11864bcbd33SKishon Vijay Abraham I 	struct omap_mcbsp_platform_data *pdata = NULL;
11964bcbd33SKishon Vijay Abraham I 	struct omap_device *od;
12078673bc8SEduardo Valentin 
12164bcbd33SKishon Vijay Abraham I 	sscanf(oh->name, "mcbsp%d", &id);
12264bcbd33SKishon Vijay Abraham I 
12364bcbd33SKishon Vijay Abraham I 	pdata = kzalloc(sizeof(struct omap_mcbsp_platform_data), GFP_KERNEL);
12464bcbd33SKishon Vijay Abraham I 	if (!pdata) {
12564bcbd33SKishon Vijay Abraham I 		pr_err("%s: No memory for mcbsp\n", __func__);
12664bcbd33SKishon Vijay Abraham I 		return -ENOMEM;
12764bcbd33SKishon Vijay Abraham I 	}
12864bcbd33SKishon Vijay Abraham I 
12964bcbd33SKishon Vijay Abraham I 	if (oh->class->rev == MCBSP_CONFIG_TYPE3) {
13064bcbd33SKishon Vijay Abraham I 		if (id == 2)
13164bcbd33SKishon Vijay Abraham I 			/* The FIFO has 1024 + 256 locations */
13264bcbd33SKishon Vijay Abraham I 			pdata->buffer_size = 0x500;
13364bcbd33SKishon Vijay Abraham I 		else
13464bcbd33SKishon Vijay Abraham I 			/* The FIFO has 128 locations */
13564bcbd33SKishon Vijay Abraham I 			pdata->buffer_size = 0x80;
13664bcbd33SKishon Vijay Abraham I 	}
13764bcbd33SKishon Vijay Abraham I 
13864bcbd33SKishon Vijay Abraham I 	oh_device[0] = oh;
13964bcbd33SKishon Vijay Abraham I 
14064bcbd33SKishon Vijay Abraham I 	if (oh->dev_attr) {
14164bcbd33SKishon Vijay Abraham I 		oh_device[1] = omap_hwmod_lookup((
14264bcbd33SKishon Vijay Abraham I 		(struct omap_mcbsp_dev_attr *)(oh->dev_attr))->sidetone);
14364bcbd33SKishon Vijay Abraham I 		count++;
14464bcbd33SKishon Vijay Abraham I 	}
14564bcbd33SKishon Vijay Abraham I 	od = omap_device_build_ss(name, id, oh_device, count, pdata,
14664bcbd33SKishon Vijay Abraham I 				sizeof(*pdata), omap2_mcbsp_latency,
14764bcbd33SKishon Vijay Abraham I 				ARRAY_SIZE(omap2_mcbsp_latency), false);
14864bcbd33SKishon Vijay Abraham I 	kfree(pdata);
14964bcbd33SKishon Vijay Abraham I 	if (IS_ERR(od))  {
15064bcbd33SKishon Vijay Abraham I 		pr_err("%s: Cant build omap_device for %s:%s.\n", __func__,
15164bcbd33SKishon Vijay Abraham I 					name, oh->name);
15264bcbd33SKishon Vijay Abraham I 		return PTR_ERR(od);
15364bcbd33SKishon Vijay Abraham I 	}
15464bcbd33SKishon Vijay Abraham I 	omap_mcbsp_count++;
15564bcbd33SKishon Vijay Abraham I 	return 0;
15664bcbd33SKishon Vijay Abraham I }
157a5b92cc3SSyed Rafiuddin 
158b4b58f58SChandra Shekhar static int __init omap2_mcbsp_init(void)
15978673bc8SEduardo Valentin {
16064bcbd33SKishon Vijay Abraham I 	omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL);
161b4b58f58SChandra Shekhar 
162b4b58f58SChandra Shekhar 	mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
163b4b58f58SChandra Shekhar 								GFP_KERNEL);
164b4b58f58SChandra Shekhar 	if (!mcbsp_ptr)
165b4b58f58SChandra Shekhar 		return -ENOMEM;
166b4b58f58SChandra Shekhar 
16778673bc8SEduardo Valentin 	return omap_mcbsp_init();
16878673bc8SEduardo Valentin }
16978673bc8SEduardo Valentin arch_initcall(omap2_mcbsp_init);
170