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 125*9cf793f9SKevin Hilman static int __init 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 } 1480c8551e5SJarkko Nikula pdata->set_clk_src = omap2_mcbsp_set_clk_src; 1490c8551e5SJarkko Nikula if (id == 1) 1500c8551e5SJarkko 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; 159da76250eSPeter Ujfalusi } else if (oh->class->rev == MCBSP_CONFIG_TYPE4) { 160da76250eSPeter Ujfalusi /* The FIFO has 128 locations for all instances */ 161da76250eSPeter Ujfalusi pdata->buffer_size = 0x80; 16264bcbd33SKishon Vijay Abraham I } 16364bcbd33SKishon Vijay Abraham I 1641a645884SJarkko Nikula if (oh->class->rev >= MCBSP_CONFIG_TYPE3) 1651a645884SJarkko Nikula pdata->has_wakeup = true; 1661a645884SJarkko Nikula 16764bcbd33SKishon Vijay Abraham I oh_device[0] = oh; 16864bcbd33SKishon Vijay Abraham I 16964bcbd33SKishon Vijay Abraham I if (oh->dev_attr) { 17064bcbd33SKishon Vijay Abraham I oh_device[1] = omap_hwmod_lookup(( 17164bcbd33SKishon Vijay Abraham I (struct omap_mcbsp_dev_attr *)(oh->dev_attr))->sidetone); 1721743d14fSJarkko Nikula pdata->enable_st_clock = omap3_enable_st_clock; 17364bcbd33SKishon Vijay Abraham I count++; 17464bcbd33SKishon Vijay Abraham I } 1753528c58eSKevin Hilman pdev = omap_device_build_ss(name, id, oh_device, count, pdata, 176f718e2c0SBenoit Cousson sizeof(*pdata), NULL, 0, false); 17764bcbd33SKishon Vijay Abraham I kfree(pdata); 1783528c58eSKevin Hilman if (IS_ERR(pdev)) { 17925985edcSLucas De Marchi pr_err("%s: Can't build omap_device for %s:%s.\n", __func__, 18064bcbd33SKishon Vijay Abraham I name, oh->name); 1813528c58eSKevin Hilman return PTR_ERR(pdev); 18264bcbd33SKishon Vijay Abraham I } 18364bcbd33SKishon Vijay Abraham I omap_mcbsp_count++; 18464bcbd33SKishon Vijay Abraham I return 0; 18564bcbd33SKishon Vijay Abraham I } 186a5b92cc3SSyed Rafiuddin 187b4b58f58SChandra Shekhar static int __init omap2_mcbsp_init(void) 18878673bc8SEduardo Valentin { 18964bcbd33SKishon Vijay Abraham I omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL); 190b4b58f58SChandra Shekhar 191b4b58f58SChandra Shekhar mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *), 192b4b58f58SChandra Shekhar GFP_KERNEL); 193b4b58f58SChandra Shekhar if (!mcbsp_ptr) 194b4b58f58SChandra Shekhar return -ENOMEM; 195b4b58f58SChandra Shekhar 19678673bc8SEduardo Valentin return omap_mcbsp_init(); 19778673bc8SEduardo Valentin } 19878673bc8SEduardo Valentin arch_initcall(omap2_mcbsp_init); 199