diff options
Diffstat (limited to 'sound/soc/codecs/arizona.c')
-rw-r--r-- | sound/soc/codecs/arizona.c | 129 |
1 files changed, 98 insertions, 31 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 802e05eae3e9..8a2221ab3d10 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -1366,7 +1366,7 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, | |||
1366 | { | 1366 | { |
1367 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 1367 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
1368 | struct arizona *arizona = priv->arizona; | 1368 | struct arizona *arizona = priv->arizona; |
1369 | struct reg_default dac_comp[] = { | 1369 | struct reg_sequence dac_comp[] = { |
1370 | { 0x80, 0x3 }, | 1370 | { 0x80, 0x3 }, |
1371 | { ARIZONA_DAC_COMP_1, 0 }, | 1371 | { ARIZONA_DAC_COMP_1, 0 }, |
1372 | { ARIZONA_DAC_COMP_2, 0 }, | 1372 | { ARIZONA_DAC_COMP_2, 0 }, |
@@ -1504,7 +1504,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
1504 | else | 1504 | else |
1505 | rates = &arizona_48k_bclk_rates[0]; | 1505 | rates = &arizona_48k_bclk_rates[0]; |
1506 | 1506 | ||
1507 | wl = snd_pcm_format_width(params_format(params)); | 1507 | wl = params_width(params); |
1508 | 1508 | ||
1509 | if (tdm_slots) { | 1509 | if (tdm_slots) { |
1510 | arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", | 1510 | arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", |
@@ -1756,17 +1756,6 @@ int arizona_init_dai(struct arizona_priv *priv, int id) | |||
1756 | } | 1756 | } |
1757 | EXPORT_SYMBOL_GPL(arizona_init_dai); | 1757 | EXPORT_SYMBOL_GPL(arizona_init_dai); |
1758 | 1758 | ||
1759 | static irqreturn_t arizona_fll_clock_ok(int irq, void *data) | ||
1760 | { | ||
1761 | struct arizona_fll *fll = data; | ||
1762 | |||
1763 | arizona_fll_dbg(fll, "clock OK\n"); | ||
1764 | |||
1765 | complete(&fll->ok); | ||
1766 | |||
1767 | return IRQ_HANDLED; | ||
1768 | } | ||
1769 | |||
1770 | static struct { | 1759 | static struct { |
1771 | unsigned int min; | 1760 | unsigned int min; |
1772 | unsigned int max; | 1761 | unsigned int max; |
@@ -2048,17 +2037,18 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll) | |||
2048 | static int arizona_enable_fll(struct arizona_fll *fll) | 2037 | static int arizona_enable_fll(struct arizona_fll *fll) |
2049 | { | 2038 | { |
2050 | struct arizona *arizona = fll->arizona; | 2039 | struct arizona *arizona = fll->arizona; |
2051 | unsigned long time_left; | ||
2052 | bool use_sync = false; | 2040 | bool use_sync = false; |
2053 | int already_enabled = arizona_is_enabled_fll(fll); | 2041 | int already_enabled = arizona_is_enabled_fll(fll); |
2054 | struct arizona_fll_cfg cfg; | 2042 | struct arizona_fll_cfg cfg; |
2043 | int i; | ||
2044 | unsigned int val; | ||
2055 | 2045 | ||
2056 | if (already_enabled < 0) | 2046 | if (already_enabled < 0) |
2057 | return already_enabled; | 2047 | return already_enabled; |
2058 | 2048 | ||
2059 | if (already_enabled) { | 2049 | if (already_enabled) { |
2060 | /* Facilitate smooth refclk across the transition */ | 2050 | /* Facilitate smooth refclk across the transition */ |
2061 | regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7, | 2051 | regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, |
2062 | ARIZONA_FLL1_GAIN_MASK, 0); | 2052 | ARIZONA_FLL1_GAIN_MASK, 0); |
2063 | regmap_update_bits_async(fll->arizona->regmap, fll->base + 1, | 2053 | regmap_update_bits_async(fll->arizona->regmap, fll->base + 1, |
2064 | ARIZONA_FLL1_FREERUN, | 2054 | ARIZONA_FLL1_FREERUN, |
@@ -2110,9 +2100,6 @@ static int arizona_enable_fll(struct arizona_fll *fll) | |||
2110 | if (!already_enabled) | 2100 | if (!already_enabled) |
2111 | pm_runtime_get(arizona->dev); | 2101 | pm_runtime_get(arizona->dev); |
2112 | 2102 | ||
2113 | /* Clear any pending completions */ | ||
2114 | try_wait_for_completion(&fll->ok); | ||
2115 | |||
2116 | regmap_update_bits_async(arizona->regmap, fll->base + 1, | 2103 | regmap_update_bits_async(arizona->regmap, fll->base + 1, |
2117 | ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); | 2104 | ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); |
2118 | if (use_sync) | 2105 | if (use_sync) |
@@ -2124,10 +2111,24 @@ static int arizona_enable_fll(struct arizona_fll *fll) | |||
2124 | regmap_update_bits_async(arizona->regmap, fll->base + 1, | 2111 | regmap_update_bits_async(arizona->regmap, fll->base + 1, |
2125 | ARIZONA_FLL1_FREERUN, 0); | 2112 | ARIZONA_FLL1_FREERUN, 0); |
2126 | 2113 | ||
2127 | time_left = wait_for_completion_timeout(&fll->ok, | 2114 | arizona_fll_dbg(fll, "Waiting for FLL lock...\n"); |
2128 | msecs_to_jiffies(250)); | 2115 | val = 0; |
2129 | if (time_left == 0) | 2116 | for (i = 0; i < 15; i++) { |
2117 | if (i < 5) | ||
2118 | usleep_range(200, 400); | ||
2119 | else | ||
2120 | msleep(20); | ||
2121 | |||
2122 | regmap_read(arizona->regmap, | ||
2123 | ARIZONA_INTERRUPT_RAW_STATUS_5, | ||
2124 | &val); | ||
2125 | if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1))) | ||
2126 | break; | ||
2127 | } | ||
2128 | if (i == 15) | ||
2130 | arizona_fll_warn(fll, "Timed out waiting for lock\n"); | 2129 | arizona_fll_warn(fll, "Timed out waiting for lock\n"); |
2130 | else | ||
2131 | arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i); | ||
2131 | 2132 | ||
2132 | return 0; | 2133 | return 0; |
2133 | } | 2134 | } |
@@ -2212,11 +2213,8 @@ EXPORT_SYMBOL_GPL(arizona_set_fll); | |||
2212 | int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, | 2213 | int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, |
2213 | int ok_irq, struct arizona_fll *fll) | 2214 | int ok_irq, struct arizona_fll *fll) |
2214 | { | 2215 | { |
2215 | int ret; | ||
2216 | unsigned int val; | 2216 | unsigned int val; |
2217 | 2217 | ||
2218 | init_completion(&fll->ok); | ||
2219 | |||
2220 | fll->id = id; | 2218 | fll->id = id; |
2221 | fll->base = base; | 2219 | fll->base = base; |
2222 | fll->arizona = arizona; | 2220 | fll->arizona = arizona; |
@@ -2238,13 +2236,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, | |||
2238 | snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), | 2236 | snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), |
2239 | "FLL%d clock OK", id); | 2237 | "FLL%d clock OK", id); |
2240 | 2238 | ||
2241 | ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name, | ||
2242 | arizona_fll_clock_ok, fll); | ||
2243 | if (ret != 0) { | ||
2244 | dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n", | ||
2245 | id, ret); | ||
2246 | } | ||
2247 | |||
2248 | regmap_update_bits(arizona->regmap, fll->base + 1, | 2239 | regmap_update_bits(arizona->regmap, fll->base + 1, |
2249 | ARIZONA_FLL1_FREERUN, 0); | 2240 | ARIZONA_FLL1_FREERUN, 0); |
2250 | 2241 | ||
@@ -2313,6 +2304,82 @@ const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = { | |||
2313 | }; | 2304 | }; |
2314 | EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls); | 2305 | EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls); |
2315 | 2306 | ||
2307 | static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b) | ||
2308 | { | ||
2309 | s16 a = be16_to_cpu(_a); | ||
2310 | s16 b = be16_to_cpu(_b); | ||
2311 | |||
2312 | if (!mode) { | ||
2313 | return abs(a) >= 4096; | ||
2314 | } else { | ||
2315 | if (abs(b) >= 4096) | ||
2316 | return true; | ||
2317 | |||
2318 | return (abs((a << 16) / (4096 - b)) >= 4096 << 4); | ||
2319 | } | ||
2320 | } | ||
2321 | |||
2322 | int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, | ||
2323 | struct snd_ctl_elem_value *ucontrol) | ||
2324 | { | ||
2325 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
2326 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | ||
2327 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
2328 | unsigned int val; | ||
2329 | __be16 *data; | ||
2330 | int len; | ||
2331 | int ret; | ||
2332 | |||
2333 | len = params->num_regs * regmap_get_val_bytes(arizona->regmap); | ||
2334 | |||
2335 | data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); | ||
2336 | if (!data) | ||
2337 | return -ENOMEM; | ||
2338 | |||
2339 | data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE); | ||
2340 | |||
2341 | if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) || | ||
2342 | arizona_eq_filter_unstable(true, data[4], data[5]) || | ||
2343 | arizona_eq_filter_unstable(true, data[8], data[9]) || | ||
2344 | arizona_eq_filter_unstable(true, data[12], data[13]) || | ||
2345 | arizona_eq_filter_unstable(false, data[16], data[17])) { | ||
2346 | dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n"); | ||
2347 | ret = -EINVAL; | ||
2348 | goto out; | ||
2349 | } | ||
2350 | |||
2351 | ret = regmap_read(arizona->regmap, params->base, &val); | ||
2352 | if (ret != 0) | ||
2353 | goto out; | ||
2354 | |||
2355 | val &= ~ARIZONA_EQ1_B1_MODE; | ||
2356 | data[0] |= cpu_to_be16(val); | ||
2357 | |||
2358 | ret = regmap_raw_write(arizona->regmap, params->base, data, len); | ||
2359 | |||
2360 | out: | ||
2361 | kfree(data); | ||
2362 | return ret; | ||
2363 | } | ||
2364 | EXPORT_SYMBOL_GPL(arizona_eq_coeff_put); | ||
2365 | |||
2366 | int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, | ||
2367 | struct snd_ctl_elem_value *ucontrol) | ||
2368 | { | ||
2369 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
2370 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | ||
2371 | __be16 *data = (__be16 *)ucontrol->value.bytes.data; | ||
2372 | s16 val = be16_to_cpu(*data); | ||
2373 | |||
2374 | if (abs(val) >= 4096) { | ||
2375 | dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n"); | ||
2376 | return -EINVAL; | ||
2377 | } | ||
2378 | |||
2379 | return snd_soc_bytes_put(kcontrol, ucontrol); | ||
2380 | } | ||
2381 | EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); | ||
2382 | |||
2316 | MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); | 2383 | MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); |
2317 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 2384 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
2318 | MODULE_LICENSE("GPL"); | 2385 | MODULE_LICENSE("GPL"); |