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