aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/mcbsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/mcbsp.c')
-rw-r--r--arch/arm/mach-omap2/mcbsp.c120
1 files changed, 72 insertions, 48 deletions
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index 4a6ef6ab8458..292eee3be15f 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -27,66 +27,69 @@
27 27
28#include "control.h" 28#include "control.h"
29 29
30/* McBSP internal signal muxing functions */ 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"
31 36
32void omap2_mcbsp1_mux_clkr_src(u8 mux) 37/* McBSP internal signal muxing function */
38static int omap2_mcbsp1_mux_rx_clk(struct device *dev, const char *signal,
39 const char *src)
33{ 40{
34 u32 v; 41 u32 v;
35 42
36 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); 43 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
37 if (mux == CLKR_SRC_CLKR)
38 v &= ~OMAP2_MCBSP1_CLKR_MASK;
39 else if (mux == CLKR_SRC_CLKX)
40 v |= OMAP2_MCBSP1_CLKR_MASK;
41 omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
42}
43EXPORT_SYMBOL(omap2_mcbsp1_mux_clkr_src);
44 44
45void omap2_mcbsp1_mux_fsr_src(u8 mux) 45 if (!strcmp(signal, "clkr")) {
46{ 46 if (!strcmp(src, "clkr"))
47 u32 v; 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 }
48 62
49 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
50 if (mux == FSR_SRC_FSR)
51 v &= ~OMAP2_MCBSP1_FSR_MASK;
52 else if (mux == FSR_SRC_FSX)
53 v |= OMAP2_MCBSP1_FSR_MASK;
54 omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0); 63 omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
64
65 return 0;
55} 66}
56EXPORT_SYMBOL(omap2_mcbsp1_mux_fsr_src);
57 67
58/* McBSP CLKS source switching function */ 68/* McBSP CLKS source switching function */
59 69static int omap2_mcbsp_set_clk_src(struct device *dev, struct clk *clk,
60int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id) 70 const char *src)
61{ 71{
62 struct omap_mcbsp *mcbsp;
63 struct clk *fck_src; 72 struct clk *fck_src;
64 char *fck_src_name; 73 char *fck_src_name;
65 int r; 74 int r;
66 75
67 if (!omap_mcbsp_check_valid_id(id)) { 76 if (!strcmp(src, "clks_ext"))
68 pr_err("%s: Invalid id (%d)\n", __func__, id + 1);
69 return -EINVAL;
70 }
71 mcbsp = id_to_mcbsp_ptr(id);
72
73 if (fck_src_id == MCBSP_CLKS_PAD_SRC)
74 fck_src_name = "pad_fck"; 77 fck_src_name = "pad_fck";
75 else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) 78 else if (!strcmp(src, "clks_fclk"))
76 fck_src_name = "prcm_fck"; 79 fck_src_name = "prcm_fck";
77 else 80 else
78 return -EINVAL; 81 return -EINVAL;
79 82
80 fck_src = clk_get(mcbsp->dev, fck_src_name); 83 fck_src = clk_get(dev, fck_src_name);
81 if (IS_ERR_OR_NULL(fck_src)) { 84 if (IS_ERR_OR_NULL(fck_src)) {
82 pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks", 85 pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks",
83 fck_src_name); 86 fck_src_name);
84 return -EINVAL; 87 return -EINVAL;
85 } 88 }
86 89
87 pm_runtime_put_sync(mcbsp->dev); 90 pm_runtime_put_sync(dev);
88 91
89 r = clk_set_parent(mcbsp->fclk, fck_src); 92 r = clk_set_parent(clk, fck_src);
90 if (IS_ERR_VALUE(r)) { 93 if (IS_ERR_VALUE(r)) {
91 pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n", 94 pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n",
92 "clks", fck_src_name); 95 "clks", fck_src_name);
@@ -94,21 +97,30 @@ int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
94 return -EINVAL; 97 return -EINVAL;
95 } 98 }
96 99
97 pm_runtime_get_sync(mcbsp->dev); 100 pm_runtime_get_sync(dev);
98 101
99 clk_put(fck_src); 102 clk_put(fck_src);
100 103
101 return 0; 104 return 0;
102} 105}
103EXPORT_SYMBOL(omap2_mcbsp_set_clks_src);
104 106
105struct omap_device_pm_latency omap2_mcbsp_latency[] = { 107static int omap3_enable_st_clock(unsigned int id, bool enable)
106 { 108{
107 .deactivate_func = omap_device_idle_hwmods, 109 unsigned int w;
108 .activate_func = omap_device_enable_hwmods, 110
109 .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, 111 /*
110 }, 112 * Sidetone uses McBSP ICLK - which must not idle when sidetones
111}; 113 * are enabled or sidetones start sounding ugly.
114 */
115 w = omap2_cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE);
116 if (enable)
117 w &= ~(1 << (id - 2));
118 else
119 w |= 1 << (id - 2);
120 omap2_cm_write_mod_reg(w, OMAP3430_PER_MOD, CM_AUTOIDLE);
121
122 return 0;
123}
112 124
113static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused) 125static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
114{ 126{
@@ -116,7 +128,7 @@ static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
116 char *name = "omap-mcbsp"; 128 char *name = "omap-mcbsp";
117 struct omap_hwmod *oh_device[2]; 129 struct omap_hwmod *oh_device[2];
118 struct omap_mcbsp_platform_data *pdata = NULL; 130 struct omap_mcbsp_platform_data *pdata = NULL;
119 struct omap_device *od; 131 struct platform_device *pdev;
120 132
121 sscanf(oh->name, "mcbsp%d", &id); 133 sscanf(oh->name, "mcbsp%d", &id);
122 134
@@ -126,7 +138,13 @@ static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
126 return -ENOMEM; 138 return -ENOMEM;
127 } 139 }
128 140
129 pdata->mcbsp_config_type = oh->class->rev; 141 pdata->reg_step = 4;
142 if (oh->class->rev < MCBSP_CONFIG_TYPE2) {
143 pdata->reg_size = 2;
144 } else {
145 pdata->reg_size = 4;
146 pdata->has_ccr = true;
147 }
130 148
131 if (oh->class->rev == MCBSP_CONFIG_TYPE3) { 149 if (oh->class->rev == MCBSP_CONFIG_TYPE3) {
132 if (id == 2) 150 if (id == 2)
@@ -137,22 +155,28 @@ static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
137 pdata->buffer_size = 0x80; 155 pdata->buffer_size = 0x80;
138 } 156 }
139 157
158 if (oh->class->rev >= MCBSP_CONFIG_TYPE3)
159 pdata->has_wakeup = true;
160
140 oh_device[0] = oh; 161 oh_device[0] = oh;
141 162
142 if (oh->dev_attr) { 163 if (oh->dev_attr) {
143 oh_device[1] = omap_hwmod_lookup(( 164 oh_device[1] = omap_hwmod_lookup((
144 (struct omap_mcbsp_dev_attr *)(oh->dev_attr))->sidetone); 165 (struct omap_mcbsp_dev_attr *)(oh->dev_attr))->sidetone);
166 pdata->enable_st_clock = omap3_enable_st_clock;
145 count++; 167 count++;
146 } 168 }
147 od = omap_device_build_ss(name, id, oh_device, count, pdata, 169 pdev = omap_device_build_ss(name, id, oh_device, count, pdata,
148 sizeof(*pdata), omap2_mcbsp_latency, 170 sizeof(*pdata), NULL, 0, false);
149 ARRAY_SIZE(omap2_mcbsp_latency), false);
150 kfree(pdata); 171 kfree(pdata);
151 if (IS_ERR(od)) { 172 if (IS_ERR(pdev)) {
152 pr_err("%s: Can't build omap_device for %s:%s.\n", __func__, 173 pr_err("%s: Can't build omap_device for %s:%s.\n", __func__,
153 name, oh->name); 174 name, oh->name);
154 return PTR_ERR(od); 175 return PTR_ERR(pdev);
155 } 176 }
177 pdata->set_clk_src = omap2_mcbsp_set_clk_src;
178 if (id == 1)
179 pdata->mux_signal = omap2_mcbsp1_mux_rx_clk;
156 omap_mcbsp_count++; 180 omap_mcbsp_count++;
157 return 0; 181 return 0;
158} 182}