xref: /linux/arch/arm/mach-omap2/mcbsp.c (revision 0c8551e5fa3833c6080542da662394817fea4616)
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>
26e95496d4SKishon Vijay Abraham I #include <linux/pm_runtime.h>
274814ced5SPaul Walmsley 
284814ced5SPaul Walmsley #include "control.h"
294814ced5SPaul Walmsley 
301743d14fSJarkko Nikula /*
311743d14fSJarkko Nikula  * FIXME: Find a mechanism to enable/disable runtime the McBSP ICLK autoidle.
321743d14fSJarkko Nikula  * Sidetone needs non-gated ICLK and sidetone autoidle is broken.
331743d14fSJarkko Nikula  */
341743d14fSJarkko Nikula #include "cm2xxx_3xxx.h"
351743d14fSJarkko Nikula #include "cm-regbits-34xx.h"
361743d14fSJarkko Nikula 
377bc0c4baSJarkko Nikula /* McBSP internal signal muxing function */
387bc0c4baSJarkko Nikula static int omap2_mcbsp1_mux_rx_clk(struct device *dev, const char *signal,
397bc0c4baSJarkko Nikula 				   const char *src)
40cf4c87abSPaul Walmsley {
41cf4c87abSPaul Walmsley 	u32 v;
42cf4c87abSPaul Walmsley 
43cf4c87abSPaul Walmsley 	v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
447bc0c4baSJarkko Nikula 
457bc0c4baSJarkko Nikula 	if (!strcmp(signal, "clkr")) {
467bc0c4baSJarkko Nikula 		if (!strcmp(src, "clkr"))
47425925ddSJarkko Nikula 			v &= ~OMAP2_MCBSP1_CLKR_MASK;
487bc0c4baSJarkko Nikula 		else if (!strcmp(src, "clkx"))
49cf4c87abSPaul Walmsley 			v |= OMAP2_MCBSP1_CLKR_MASK;
507bc0c4baSJarkko Nikula 		else
517bc0c4baSJarkko Nikula 			return -EINVAL;
527bc0c4baSJarkko Nikula 	} else if (!strcmp(signal, "fsr")) {
537bc0c4baSJarkko Nikula 		if (!strcmp(src, "fsr"))
54425925ddSJarkko Nikula 			v &= ~OMAP2_MCBSP1_FSR_MASK;
557bc0c4baSJarkko Nikula 		else if (!strcmp(src, "fsx"))
56cf4c87abSPaul Walmsley 			v |= OMAP2_MCBSP1_FSR_MASK;
577bc0c4baSJarkko Nikula 		else
587bc0c4baSJarkko Nikula 			return -EINVAL;
597bc0c4baSJarkko Nikula 	} else {
607bc0c4baSJarkko Nikula 		return -EINVAL;
61cf4c87abSPaul Walmsley 	}
627bc0c4baSJarkko Nikula 
637bc0c4baSJarkko Nikula 	omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
647bc0c4baSJarkko Nikula 
657bc0c4baSJarkko Nikula 	return 0;
667bc0c4baSJarkko Nikula }
67cf4c87abSPaul Walmsley 
68d1358657SPaul Walmsley /* McBSP CLKS source switching function */
6909d28d2cSJarkko Nikula static int omap2_mcbsp_set_clk_src(struct device *dev, struct clk *clk,
7009d28d2cSJarkko Nikula 				   const char *src)
71d1358657SPaul Walmsley {
72d1358657SPaul Walmsley 	struct clk *fck_src;
73d1358657SPaul Walmsley 	char *fck_src_name;
74d1358657SPaul Walmsley 	int r;
75d1358657SPaul Walmsley 
7609d28d2cSJarkko Nikula 	if (!strcmp(src, "clks_ext"))
77d1358657SPaul Walmsley 		fck_src_name = "pad_fck";
7809d28d2cSJarkko Nikula 	else if (!strcmp(src, "clks_fclk"))
79d1358657SPaul Walmsley 		fck_src_name = "prcm_fck";
80d1358657SPaul Walmsley 	else
81d1358657SPaul Walmsley 		return -EINVAL;
82d1358657SPaul Walmsley 
8309d28d2cSJarkko Nikula 	fck_src = clk_get(dev, fck_src_name);
84d1358657SPaul Walmsley 	if (IS_ERR_OR_NULL(fck_src)) {
85d1358657SPaul Walmsley 		pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks",
86d1358657SPaul Walmsley 		       fck_src_name);
87d1358657SPaul Walmsley 		return -EINVAL;
88d1358657SPaul Walmsley 	}
89d1358657SPaul Walmsley 
9009d28d2cSJarkko Nikula 	pm_runtime_put_sync(dev);
91d1358657SPaul Walmsley 
9209d28d2cSJarkko Nikula 	r = clk_set_parent(clk, fck_src);
93d1358657SPaul Walmsley 	if (IS_ERR_VALUE(r)) {
94d1358657SPaul Walmsley 		pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n",
95d1358657SPaul Walmsley 		       "clks", fck_src_name);
96d1358657SPaul Walmsley 		clk_put(fck_src);
97d1358657SPaul Walmsley 		return -EINVAL;
98d1358657SPaul Walmsley 	}
99d1358657SPaul Walmsley 
10009d28d2cSJarkko Nikula 	pm_runtime_get_sync(dev);
101d1358657SPaul Walmsley 
102d1358657SPaul Walmsley 	clk_put(fck_src);
103d1358657SPaul Walmsley 
104d1358657SPaul Walmsley 	return 0;
105d1358657SPaul Walmsley }
106d1358657SPaul Walmsley 
1071743d14fSJarkko Nikula static int omap3_enable_st_clock(unsigned int id, bool enable)
1081743d14fSJarkko Nikula {
1091743d14fSJarkko Nikula 	unsigned int w;
1101743d14fSJarkko Nikula 
1111743d14fSJarkko Nikula 	/*
1121743d14fSJarkko Nikula 	 * Sidetone uses McBSP ICLK - which must not idle when sidetones
1131743d14fSJarkko Nikula 	 * are enabled or sidetones start sounding ugly.
1141743d14fSJarkko Nikula 	 */
1151743d14fSJarkko Nikula 	w = omap2_cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE);
1161743d14fSJarkko Nikula 	if (enable)
1171743d14fSJarkko Nikula 		w &= ~(1 << (id - 2));
1181743d14fSJarkko Nikula 	else
1191743d14fSJarkko Nikula 		w |= 1 << (id - 2);
1201743d14fSJarkko Nikula 	omap2_cm_write_mod_reg(w, OMAP3430_PER_MOD, CM_AUTOIDLE);
1211743d14fSJarkko Nikula 
1221743d14fSJarkko Nikula 	return 0;
1231743d14fSJarkko Nikula }
1241743d14fSJarkko Nikula 
12564bcbd33SKishon Vijay Abraham I static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
12678673bc8SEduardo Valentin {
12764bcbd33SKishon Vijay Abraham I 	int id, count = 1;
12864bcbd33SKishon Vijay Abraham I 	char *name = "omap-mcbsp";
12964bcbd33SKishon Vijay Abraham I 	struct omap_hwmod *oh_device[2];
13064bcbd33SKishon Vijay Abraham I 	struct omap_mcbsp_platform_data *pdata = NULL;
1313528c58eSKevin Hilman 	struct platform_device *pdev;
13278673bc8SEduardo Valentin 
13364bcbd33SKishon Vijay Abraham I 	sscanf(oh->name, "mcbsp%d", &id);
13464bcbd33SKishon Vijay Abraham I 
13564bcbd33SKishon Vijay Abraham I 	pdata = kzalloc(sizeof(struct omap_mcbsp_platform_data), GFP_KERNEL);
13664bcbd33SKishon Vijay Abraham I 	if (!pdata) {
13764bcbd33SKishon Vijay Abraham I 		pr_err("%s: No memory for mcbsp\n", __func__);
13864bcbd33SKishon Vijay Abraham I 		return -ENOMEM;
13964bcbd33SKishon Vijay Abraham I 	}
14064bcbd33SKishon Vijay Abraham I 
141cdc71514SJarkko Nikula 	pdata->reg_step = 4;
14288408230SJarkko Nikula 	if (oh->class->rev < MCBSP_CONFIG_TYPE2) {
143cdc71514SJarkko Nikula 		pdata->reg_size = 2;
14488408230SJarkko Nikula 	} else {
145cdc71514SJarkko Nikula 		pdata->reg_size = 4;
14688408230SJarkko Nikula 		pdata->has_ccr = true;
14788408230SJarkko Nikula 	}
148*0c8551e5SJarkko Nikula 	pdata->set_clk_src = omap2_mcbsp_set_clk_src;
149*0c8551e5SJarkko Nikula 	if (id == 1)
150*0c8551e5SJarkko Nikula 		pdata->mux_signal = omap2_mcbsp1_mux_rx_clk;
1519504ba64SKishon Vijay Abraham I 
15264bcbd33SKishon Vijay Abraham I 	if (oh->class->rev == MCBSP_CONFIG_TYPE3) {
15364bcbd33SKishon Vijay Abraham I 		if (id == 2)
15464bcbd33SKishon Vijay Abraham I 			/* The FIFO has 1024 + 256 locations */
15564bcbd33SKishon Vijay Abraham I 			pdata->buffer_size = 0x500;
15664bcbd33SKishon Vijay Abraham I 		else
15764bcbd33SKishon Vijay Abraham I 			/* The FIFO has 128 locations */
15864bcbd33SKishon Vijay Abraham I 			pdata->buffer_size = 0x80;
15964bcbd33SKishon Vijay Abraham I 	}
16064bcbd33SKishon Vijay Abraham I 
1611a645884SJarkko Nikula 	if (oh->class->rev >= MCBSP_CONFIG_TYPE3)
1621a645884SJarkko Nikula 		pdata->has_wakeup = true;
1631a645884SJarkko Nikula 
16464bcbd33SKishon Vijay Abraham I 	oh_device[0] = oh;
16564bcbd33SKishon Vijay Abraham I 
16664bcbd33SKishon Vijay Abraham I 	if (oh->dev_attr) {
16764bcbd33SKishon Vijay Abraham I 		oh_device[1] = omap_hwmod_lookup((
16864bcbd33SKishon Vijay Abraham I 		(struct omap_mcbsp_dev_attr *)(oh->dev_attr))->sidetone);
1691743d14fSJarkko Nikula 		pdata->enable_st_clock = omap3_enable_st_clock;
17064bcbd33SKishon Vijay Abraham I 		count++;
17164bcbd33SKishon Vijay Abraham I 	}
1723528c58eSKevin Hilman 	pdev = omap_device_build_ss(name, id, oh_device, count, pdata,
173f718e2c0SBenoit Cousson 				sizeof(*pdata), NULL, 0, false);
17464bcbd33SKishon Vijay Abraham I 	kfree(pdata);
1753528c58eSKevin Hilman 	if (IS_ERR(pdev))  {
17625985edcSLucas De Marchi 		pr_err("%s: Can't build omap_device for %s:%s.\n", __func__,
17764bcbd33SKishon Vijay Abraham I 					name, oh->name);
1783528c58eSKevin Hilman 		return PTR_ERR(pdev);
17964bcbd33SKishon Vijay Abraham I 	}
18064bcbd33SKishon Vijay Abraham I 	omap_mcbsp_count++;
18164bcbd33SKishon Vijay Abraham I 	return 0;
18264bcbd33SKishon Vijay Abraham I }
183a5b92cc3SSyed Rafiuddin 
184b4b58f58SChandra Shekhar static int __init omap2_mcbsp_init(void)
18578673bc8SEduardo Valentin {
18664bcbd33SKishon Vijay Abraham I 	omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL);
187b4b58f58SChandra Shekhar 
188b4b58f58SChandra Shekhar 	mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
189b4b58f58SChandra Shekhar 								GFP_KERNEL);
190b4b58f58SChandra Shekhar 	if (!mcbsp_ptr)
191b4b58f58SChandra Shekhar 		return -ENOMEM;
192b4b58f58SChandra Shekhar 
19378673bc8SEduardo Valentin 	return omap_mcbsp_init();
19478673bc8SEduardo Valentin }
19578673bc8SEduardo Valentin arch_initcall(omap2_mcbsp_init);
196