| Eduardo Valentin | 78673bc | 2008-07-03 12:24:40 +0300 | [diff] [blame] | 1 | /* | 
 | 2 |  * linux/arch/arm/mach-omap2/mcbsp.c | 
 | 3 |  * | 
 | 4 |  * Copyright (C) 2008 Instituto Nokia de Tecnologia | 
 | 5 |  * Contact: Eduardo Valentin <eduardo.valentin@indt.org.br> | 
 | 6 |  * | 
 | 7 |  * This program is free software; you can redistribute it and/or modify | 
 | 8 |  * it under the terms of the GNU General Public License version 2 as | 
 | 9 |  * published by the Free Software Foundation. | 
 | 10 |  * | 
 | 11 |  * Multichannel mode not supported. | 
 | 12 |  */ | 
 | 13 | #include <linux/module.h> | 
 | 14 | #include <linux/init.h> | 
 | 15 | #include <linux/clk.h> | 
 | 16 | #include <linux/err.h> | 
 | 17 | #include <linux/io.h> | 
 | 18 | #include <linux/platform_device.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 19 | #include <linux/slab.h> | 
| Eduardo Valentin | 78673bc | 2008-07-03 12:24:40 +0300 | [diff] [blame] | 20 |  | 
| Tony Lindgren | dd7667a | 2009-01-15 13:09:51 +0200 | [diff] [blame] | 21 | #include <mach/irqs.h> | 
| Tony Lindgren | ce491cf | 2009-10-20 09:40:47 -0700 | [diff] [blame] | 22 | #include <plat/dma.h> | 
| Tony Lindgren | ce491cf | 2009-10-20 09:40:47 -0700 | [diff] [blame] | 23 | #include <plat/cpu.h> | 
 | 24 | #include <plat/mcbsp.h> | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 25 | #include <plat/omap_device.h> | 
| Kishon Vijay Abraham I | e95496d | 2011-02-24 15:16:54 +0530 | [diff] [blame] | 26 | #include <linux/pm_runtime.h> | 
| Paul Walmsley | 4814ced | 2010-10-08 11:40:20 -0600 | [diff] [blame] | 27 |  | 
 | 28 | #include "control.h" | 
 | 29 |  | 
| Jarkko Nikula | 1743d14 | 2011-09-26 10:45:44 +0300 | [diff] [blame] | 30 | /* | 
 | 31 |  * FIXME: Find a mechanism to enable/disable runtime the McBSP ICLK autoidle. | 
 | 32 |  * Sidetone needs non-gated ICLK and sidetone autoidle is broken. | 
 | 33 |  */ | 
 | 34 | #include "cm2xxx_3xxx.h" | 
 | 35 | #include "cm-regbits-34xx.h" | 
 | 36 |  | 
| Peter Ujfalusi | 40c0764 | 2012-03-08 11:08:36 +0200 | [diff] [blame] | 37 | /* McBSP1 internal signal muxing function for OMAP2/3 */ | 
| Jarkko Nikula | 7bc0c4b | 2011-09-26 10:45:49 +0300 | [diff] [blame] | 38 | static int omap2_mcbsp1_mux_rx_clk(struct device *dev, const char *signal, | 
 | 39 | 				   const char *src) | 
| Paul Walmsley | cf4c87a | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 40 | { | 
 | 41 | 	u32 v; | 
 | 42 |  | 
 | 43 | 	v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); | 
| Paul Walmsley | cf4c87a | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 44 |  | 
| Jarkko Nikula | 7bc0c4b | 2011-09-26 10:45:49 +0300 | [diff] [blame] | 45 | 	if (!strcmp(signal, "clkr")) { | 
 | 46 | 		if (!strcmp(src, "clkr")) | 
 | 47 | 			v &= ~OMAP2_MCBSP1_CLKR_MASK; | 
 | 48 | 		else if (!strcmp(src, "clkx")) | 
 | 49 | 			v |= OMAP2_MCBSP1_CLKR_MASK; | 
 | 50 | 		else | 
 | 51 | 			return -EINVAL; | 
 | 52 | 	} else if (!strcmp(signal, "fsr")) { | 
 | 53 | 		if (!strcmp(src, "fsr")) | 
 | 54 | 			v &= ~OMAP2_MCBSP1_FSR_MASK; | 
 | 55 | 		else if (!strcmp(src, "fsx")) | 
 | 56 | 			v |= OMAP2_MCBSP1_FSR_MASK; | 
 | 57 | 		else | 
 | 58 | 			return -EINVAL; | 
 | 59 | 	} else { | 
 | 60 | 		return -EINVAL; | 
 | 61 | 	} | 
| Paul Walmsley | cf4c87a | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 62 |  | 
| Paul Walmsley | cf4c87a | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 63 | 	omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0); | 
| Jarkko Nikula | 7bc0c4b | 2011-09-26 10:45:49 +0300 | [diff] [blame] | 64 |  | 
 | 65 | 	return 0; | 
| Paul Walmsley | cf4c87a | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 66 | } | 
| Paul Walmsley | cf4c87a | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 67 |  | 
| Peter Ujfalusi | 40c0764 | 2012-03-08 11:08:36 +0200 | [diff] [blame] | 68 | /* McBSP4 internal signal muxing function for OMAP4 */ | 
 | 69 | #define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX	(1 << 31) | 
 | 70 | #define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX	(1 << 30) | 
 | 71 | static int omap4_mcbsp4_mux_rx_clk(struct device *dev, const char *signal, | 
 | 72 | 				   const char *src) | 
 | 73 | { | 
 | 74 | 	u32 v; | 
 | 75 |  | 
 | 76 | 	/* | 
 | 77 | 	 * In CONTROL_MCBSPLP register only bit 30 (CLKR mux), and bit 31 (FSR | 
 | 78 | 	 * mux) is used */ | 
 | 79 | 	v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP); | 
 | 80 |  | 
 | 81 | 	if (!strcmp(signal, "clkr")) { | 
 | 82 | 		if (!strcmp(src, "clkr")) | 
 | 83 | 			v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX; | 
 | 84 | 		else if (!strcmp(src, "clkx")) | 
 | 85 | 			v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX; | 
 | 86 | 		else | 
 | 87 | 			return -EINVAL; | 
 | 88 | 	} else if (!strcmp(signal, "fsr")) { | 
 | 89 | 		if (!strcmp(src, "fsr")) | 
 | 90 | 			v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX; | 
 | 91 | 		else if (!strcmp(src, "fsx")) | 
 | 92 | 			v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX; | 
 | 93 | 		else | 
 | 94 | 			return -EINVAL; | 
 | 95 | 	} else { | 
 | 96 | 		return -EINVAL; | 
 | 97 | 	} | 
 | 98 |  | 
 | 99 | 	omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP); | 
 | 100 |  | 
 | 101 | 	return 0; | 
 | 102 | } | 
 | 103 |  | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 104 | /* McBSP CLKS source switching function */ | 
| Jarkko Nikula | 09d28d2 | 2011-09-26 10:45:48 +0300 | [diff] [blame] | 105 | static int omap2_mcbsp_set_clk_src(struct device *dev, struct clk *clk, | 
 | 106 | 				   const char *src) | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 107 | { | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 108 | 	struct clk *fck_src; | 
 | 109 | 	char *fck_src_name; | 
 | 110 | 	int r; | 
 | 111 |  | 
| Jarkko Nikula | 09d28d2 | 2011-09-26 10:45:48 +0300 | [diff] [blame] | 112 | 	if (!strcmp(src, "clks_ext")) | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 113 | 		fck_src_name = "pad_fck"; | 
| Jarkko Nikula | 09d28d2 | 2011-09-26 10:45:48 +0300 | [diff] [blame] | 114 | 	else if (!strcmp(src, "clks_fclk")) | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 115 | 		fck_src_name = "prcm_fck"; | 
 | 116 | 	else | 
 | 117 | 		return -EINVAL; | 
 | 118 |  | 
| Jarkko Nikula | 09d28d2 | 2011-09-26 10:45:48 +0300 | [diff] [blame] | 119 | 	fck_src = clk_get(dev, fck_src_name); | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 120 | 	if (IS_ERR_OR_NULL(fck_src)) { | 
 | 121 | 		pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks", | 
 | 122 | 		       fck_src_name); | 
 | 123 | 		return -EINVAL; | 
 | 124 | 	} | 
 | 125 |  | 
| Jarkko Nikula | 09d28d2 | 2011-09-26 10:45:48 +0300 | [diff] [blame] | 126 | 	pm_runtime_put_sync(dev); | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 127 |  | 
| Jarkko Nikula | 09d28d2 | 2011-09-26 10:45:48 +0300 | [diff] [blame] | 128 | 	r = clk_set_parent(clk, fck_src); | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 129 | 	if (IS_ERR_VALUE(r)) { | 
 | 130 | 		pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n", | 
 | 131 | 		       "clks", fck_src_name); | 
 | 132 | 		clk_put(fck_src); | 
 | 133 | 		return -EINVAL; | 
 | 134 | 	} | 
 | 135 |  | 
| Jarkko Nikula | 09d28d2 | 2011-09-26 10:45:48 +0300 | [diff] [blame] | 136 | 	pm_runtime_get_sync(dev); | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 137 |  | 
 | 138 | 	clk_put(fck_src); | 
 | 139 |  | 
 | 140 | 	return 0; | 
 | 141 | } | 
| Paul Walmsley | d135865 | 2010-10-08 11:40:19 -0600 | [diff] [blame] | 142 |  | 
| Jarkko Nikula | 1743d14 | 2011-09-26 10:45:44 +0300 | [diff] [blame] | 143 | static int omap3_enable_st_clock(unsigned int id, bool enable) | 
 | 144 | { | 
 | 145 | 	unsigned int w; | 
 | 146 |  | 
 | 147 | 	/* | 
 | 148 | 	 * Sidetone uses McBSP ICLK - which must not idle when sidetones | 
 | 149 | 	 * are enabled or sidetones start sounding ugly. | 
 | 150 | 	 */ | 
 | 151 | 	w = omap2_cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE); | 
 | 152 | 	if (enable) | 
 | 153 | 		w &= ~(1 << (id - 2)); | 
 | 154 | 	else | 
 | 155 | 		w |= 1 << (id - 2); | 
 | 156 | 	omap2_cm_write_mod_reg(w, OMAP3430_PER_MOD, CM_AUTOIDLE); | 
 | 157 |  | 
 | 158 | 	return 0; | 
 | 159 | } | 
 | 160 |  | 
| Kevin Hilman | 9cf793f | 2012-02-20 09:43:30 -0800 | [diff] [blame] | 161 | static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused) | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 162 | { | 
 | 163 | 	int id, count = 1; | 
 | 164 | 	char *name = "omap-mcbsp"; | 
 | 165 | 	struct omap_hwmod *oh_device[2]; | 
 | 166 | 	struct omap_mcbsp_platform_data *pdata = NULL; | 
| Kevin Hilman | 3528c58 | 2011-07-21 13:48:45 -0700 | [diff] [blame] | 167 | 	struct platform_device *pdev; | 
| Eduardo Valentin | 78673bc | 2008-07-03 12:24:40 +0300 | [diff] [blame] | 168 |  | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 169 | 	sscanf(oh->name, "mcbsp%d", &id); | 
 | 170 |  | 
 | 171 | 	pdata = kzalloc(sizeof(struct omap_mcbsp_platform_data), GFP_KERNEL); | 
 | 172 | 	if (!pdata) { | 
 | 173 | 		pr_err("%s: No memory for mcbsp\n", __func__); | 
 | 174 | 		return -ENOMEM; | 
 | 175 | 	} | 
 | 176 |  | 
| Jarkko Nikula | cdc71514 | 2011-09-26 10:45:39 +0300 | [diff] [blame] | 177 | 	pdata->reg_step = 4; | 
| Jarkko Nikula | 8840823 | 2011-09-26 10:45:41 +0300 | [diff] [blame] | 178 | 	if (oh->class->rev < MCBSP_CONFIG_TYPE2) { | 
| Jarkko Nikula | cdc71514 | 2011-09-26 10:45:39 +0300 | [diff] [blame] | 179 | 		pdata->reg_size = 2; | 
| Jarkko Nikula | 8840823 | 2011-09-26 10:45:41 +0300 | [diff] [blame] | 180 | 	} else { | 
| Jarkko Nikula | cdc71514 | 2011-09-26 10:45:39 +0300 | [diff] [blame] | 181 | 		pdata->reg_size = 4; | 
| Jarkko Nikula | 8840823 | 2011-09-26 10:45:41 +0300 | [diff] [blame] | 182 | 		pdata->has_ccr = true; | 
 | 183 | 	} | 
| Jarkko Nikula | 0c8551e | 2011-12-12 10:38:26 +0200 | [diff] [blame] | 184 | 	pdata->set_clk_src = omap2_mcbsp_set_clk_src; | 
| Peter Ujfalusi | 40c0764 | 2012-03-08 11:08:36 +0200 | [diff] [blame] | 185 |  | 
 | 186 | 	/* On OMAP2/3 the McBSP1 port has 6 pin configuration */ | 
 | 187 | 	if (id == 1 && oh->class->rev < MCBSP_CONFIG_TYPE4) | 
| Jarkko Nikula | 0c8551e | 2011-12-12 10:38:26 +0200 | [diff] [blame] | 188 | 		pdata->mux_signal = omap2_mcbsp1_mux_rx_clk; | 
| Kishon Vijay Abraham I | 9504ba6 | 2011-02-24 15:16:55 +0530 | [diff] [blame] | 189 |  | 
| Peter Ujfalusi | 40c0764 | 2012-03-08 11:08:36 +0200 | [diff] [blame] | 190 | 	/* On OMAP4 the McBSP4 port has 6 pin configuration */ | 
 | 191 | 	if (id == 4 && oh->class->rev == MCBSP_CONFIG_TYPE4) | 
 | 192 | 		pdata->mux_signal = omap4_mcbsp4_mux_rx_clk; | 
 | 193 |  | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 194 | 	if (oh->class->rev == MCBSP_CONFIG_TYPE3) { | 
 | 195 | 		if (id == 2) | 
 | 196 | 			/* The FIFO has 1024 + 256 locations */ | 
 | 197 | 			pdata->buffer_size = 0x500; | 
 | 198 | 		else | 
 | 199 | 			/* The FIFO has 128 locations */ | 
 | 200 | 			pdata->buffer_size = 0x80; | 
| Peter Ujfalusi | da76250 | 2011-12-15 11:32:26 +0200 | [diff] [blame] | 201 | 	} else if (oh->class->rev == MCBSP_CONFIG_TYPE4) { | 
 | 202 | 		/* The FIFO has 128 locations for all instances */ | 
 | 203 | 		pdata->buffer_size = 0x80; | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 204 | 	} | 
 | 205 |  | 
| Jarkko Nikula | 1a64588 | 2011-09-26 10:45:40 +0300 | [diff] [blame] | 206 | 	if (oh->class->rev >= MCBSP_CONFIG_TYPE3) | 
 | 207 | 		pdata->has_wakeup = true; | 
 | 208 |  | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 209 | 	oh_device[0] = oh; | 
 | 210 |  | 
 | 211 | 	if (oh->dev_attr) { | 
 | 212 | 		oh_device[1] = omap_hwmod_lookup(( | 
 | 213 | 		(struct omap_mcbsp_dev_attr *)(oh->dev_attr))->sidetone); | 
| Jarkko Nikula | 1743d14 | 2011-09-26 10:45:44 +0300 | [diff] [blame] | 214 | 		pdata->enable_st_clock = omap3_enable_st_clock; | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 215 | 		count++; | 
 | 216 | 	} | 
| Kevin Hilman | 3528c58 | 2011-07-21 13:48:45 -0700 | [diff] [blame] | 217 | 	pdev = omap_device_build_ss(name, id, oh_device, count, pdata, | 
| Benoit Cousson | f718e2c | 2011-08-10 15:30:09 +0200 | [diff] [blame] | 218 | 				sizeof(*pdata), NULL, 0, false); | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 219 | 	kfree(pdata); | 
| Kevin Hilman | 3528c58 | 2011-07-21 13:48:45 -0700 | [diff] [blame] | 220 | 	if (IS_ERR(pdev))  { | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 221 | 		pr_err("%s: Can't build omap_device for %s:%s.\n", __func__, | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 222 | 					name, oh->name); | 
| Kevin Hilman | 3528c58 | 2011-07-21 13:48:45 -0700 | [diff] [blame] | 223 | 		return PTR_ERR(pdev); | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 224 | 	} | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 225 | 	return 0; | 
 | 226 | } | 
| Syed Rafiuddin | a5b92cc | 2009-07-28 18:57:10 +0530 | [diff] [blame] | 227 |  | 
| Chandra Shekhar | b4b58f5 | 2008-10-08 10:01:39 +0300 | [diff] [blame] | 228 | static int __init omap2_mcbsp_init(void) | 
| Eduardo Valentin | 78673bc | 2008-07-03 12:24:40 +0300 | [diff] [blame] | 229 | { | 
| Kishon Vijay Abraham I | 64bcbd3 | 2011-02-24 15:16:52 +0530 | [diff] [blame] | 230 | 	omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL); | 
| Chandra Shekhar | b4b58f5 | 2008-10-08 10:01:39 +0300 | [diff] [blame] | 231 |  | 
| Peter Ujfalusi | 0210dc4 | 2012-01-26 12:38:31 +0200 | [diff] [blame] | 232 | 	return 0; | 
| Eduardo Valentin | 78673bc | 2008-07-03 12:24:40 +0300 | [diff] [blame] | 233 | } | 
 | 234 | arch_initcall(omap2_mcbsp_init); |