int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; char *name; unsigned int reg; unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK; unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT; unsigned int *clk; switch (clk_id) { case ARIZONA_CLK_SYSCLK: name = "SYSCLK"; reg = ARIZONA_SYSTEM_CLOCK_1; clk = &priv->sysclk; mask |= ARIZONA_SYSCLK_FRAC; break; case ARIZONA_CLK_ASYNCCLK: name = "ASYNCCLK"; reg = ARIZONA_ASYNC_CLOCK_1; clk = &priv->asyncclk; break; case ARIZONA_CLK_OPCLK: case ARIZONA_CLK_ASYNC_OPCLK: return arizona_set_opclk(codec, clk_id, freq); default: return -EINVAL; } switch (freq) { case 5644800: case 6144000: break; case 11289600: case 12288000: val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 22579200: case 24576000: val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 45158400: case 49152000: val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT; break; default: return -EINVAL; } *clk = freq; if (freq % 6144000) val |= ARIZONA_SYSCLK_FRAC; dev_dbg(arizona->dev, "%s set to %uHz", name, freq); return regmap_update_bits(arizona->regmap, reg, mask, val); }
int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; char *name; unsigned int reg; unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK; unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT; unsigned int *clk; int ret; switch (clk_id) { case ARIZONA_CLK_SYSCLK: name = "SYSCLK"; reg = ARIZONA_SYSTEM_CLOCK_1; clk = &priv->sysclk; mask |= ARIZONA_SYSCLK_FRAC; break; case ARIZONA_CLK_ASYNCCLK: name = "ASYNCCLK"; reg = ARIZONA_ASYNC_CLOCK_1; clk = &priv->asyncclk; break; case ARIZONA_CLK_OPCLK: case ARIZONA_CLK_ASYNC_OPCLK: return arizona_set_opclk(codec, clk_id, freq); default: return -EINVAL; } switch (freq) { case 5644800: case 6144000: break; case 11289600: case 12288000: val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 22579200: case 24576000: val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 45158400: case 49152000: val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 67737600: case 73728000: val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 90316800: case 98304000: val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 135475200: case 147456000: val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 0: dev_dbg(arizona->dev, "%s cleared\n", name); *clk = freq; return 0; default: return -EINVAL; } if (arizona->dcvdd_lp_fmax && (freq > arizona->dcvdd_lp_fmax)) { ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000); if (ret != 0) { dev_err(arizona->dev, "Failed to raise DCVDD %d\n", ret); return ret; } } *clk = freq; if (freq % 6144000) val |= ARIZONA_SYSCLK_FRAC; dev_dbg(arizona->dev, "%s set to %uHz", name, freq); ret = regmap_update_bits(arizona->regmap, reg, mask, val); if (ret != 0) return ret; if (arizona->dcvdd_lp_fmax) { if (priv->sysclk <= arizona->dcvdd_lp_fmax && priv->asyncclk <= arizona->dcvdd_lp_fmax) { ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000); if (ret != 0) dev_warn(arizona->dev, "Failed to lower DCVDD %d\n", ret); } } return 0; }