clk: cs2000-cp: convert driver to regmap

Regmap gives us caching, debugging infrastructure and other things for
free and does away with open-coded bit-fiddling implementations.

Signed-off-by: Daniel Mack <daniel@zonque.org>
Link: https://lore.kernel.org/r/20220125093336.226787-10-daniel@zonque.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
Daniel Mack 2022-01-25 10:33:36 +01:00 committed by Stephen Boyd
parent 2f3d32fe9d
commit 5edffb9805
2 changed files with 69 additions and 56 deletions

View File

@ -197,6 +197,7 @@ config COMMON_CLK_CDCE925
config COMMON_CLK_CS2000_CP config COMMON_CLK_CS2000_CP
tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier" tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier"
depends on I2C depends on I2C
select REGMAP_I2C
help help
If you say yes here you get support for the CS2000 clock multiplier. If you say yes here you get support for the CS2000 clock multiplier.

View File

@ -11,6 +11,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/regmap.h>
#define CH_MAX 4 #define CH_MAX 4
#define RATIO_REG_SIZE 4 #define RATIO_REG_SIZE 4
@ -74,11 +75,36 @@
#define REF_CLK 1 #define REF_CLK 1
#define CLK_MAX 2 #define CLK_MAX 2
static bool cs2000_readable_reg(struct device *dev, unsigned int reg)
{
return reg > 0;
}
static bool cs2000_writeable_reg(struct device *dev, unsigned int reg)
{
return reg != DEVICE_ID;
}
static bool cs2000_volatile_reg(struct device *dev, unsigned int reg)
{
return reg == DEVICE_CTRL;
}
static const struct regmap_config cs2000_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = FUNC_CFG2,
.readable_reg = cs2000_readable_reg,
.writeable_reg = cs2000_writeable_reg,
.volatile_reg = cs2000_volatile_reg,
};
struct cs2000_priv { struct cs2000_priv {
struct clk_hw hw; struct clk_hw hw;
struct i2c_client *client; struct i2c_client *client;
struct clk *clk_in; struct clk *clk_in;
struct clk *ref_clk; struct clk *ref_clk;
struct regmap *regmap;
bool dynamic_mode; bool dynamic_mode;
bool lf_ratio; bool lf_ratio;
@ -101,41 +127,22 @@ static const struct i2c_device_id cs2000_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, cs2000_id); MODULE_DEVICE_TABLE(i2c, cs2000_id);
#define cs2000_read(priv, addr) \
i2c_smbus_read_byte_data(priv_to_client(priv), addr)
#define cs2000_write(priv, addr, val) \
i2c_smbus_write_byte_data(priv_to_client(priv), addr, val)
static int cs2000_bset(struct cs2000_priv *priv, u8 addr, u8 mask, u8 val)
{
s32 data;
data = cs2000_read(priv, addr);
if (data < 0)
return data;
data &= ~mask;
data |= (val & mask);
return cs2000_write(priv, addr, data);
}
static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable) static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable)
{ {
int ret; int ret;
ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1, ret = regmap_update_bits(priv->regmap, DEVICE_CFG1, ENDEV1,
enable ? ENDEV1 : 0); enable ? ENDEV1 : 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = cs2000_bset(priv, GLOBAL_CFG, ENDEV2, ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, ENDEV2,
enable ? ENDEV2 : 0); enable ? ENDEV2 : 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = cs2000_bset(priv, FUNC_CFG1, CLKSKIPEN, ret = regmap_update_bits(priv->regmap, FUNC_CFG1, CLKSKIPEN,
(enable && priv->clk_skip) ? CLKSKIPEN : 0); (enable && priv->clk_skip) ? CLKSKIPEN : 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -156,21 +163,21 @@ static int cs2000_ref_clk_bound_rate(struct cs2000_priv *priv,
else else
return -EINVAL; return -EINVAL;
return cs2000_bset(priv, FUNC_CFG1, return regmap_update_bits(priv->regmap, FUNC_CFG1,
REFCLKDIV_MASK, REFCLKDIV_MASK,
REFCLKDIV(val)); REFCLKDIV(val));
} }
static int cs2000_wait_pll_lock(struct cs2000_priv *priv) static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
{ {
struct device *dev = priv_to_dev(priv); struct device *dev = priv_to_dev(priv);
s32 val; unsigned int i, val;
unsigned int i; int ret;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
val = cs2000_read(priv, DEVICE_CTRL); ret = regmap_read(priv->regmap, DEVICE_CTRL, &val);
if (val < 0) if (ret < 0)
return val; return ret;
if (!(val & PLL_UNLOCK)) if (!(val & PLL_UNLOCK))
return 0; return 0;
udelay(1); udelay(1);
@ -184,10 +191,10 @@ static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable) static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable)
{ {
/* enable both AUX_OUT, CLK_OUT */ /* enable both AUX_OUT, CLK_OUT */
return cs2000_bset(priv, DEVICE_CTRL, return regmap_update_bits(priv->regmap, DEVICE_CTRL,
(AUXOUTDIS | CLKOUTDIS), (AUXOUTDIS | CLKOUTDIS),
enable ? 0 : enable ? 0 :
(AUXOUTDIS | CLKOUTDIS)); (AUXOUTDIS | CLKOUTDIS));
} }
static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out, bool lf_ratio) static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out, bool lf_ratio)
@ -235,7 +242,7 @@ static int cs2000_ratio_set(struct cs2000_priv *priv,
val = cs2000_rate_to_ratio(rate_in, rate_out, priv->lf_ratio); val = cs2000_rate_to_ratio(rate_in, rate_out, priv->lf_ratio);
for (i = 0; i < RATIO_REG_SIZE; i++) { for (i = 0; i < RATIO_REG_SIZE; i++) {
ret = cs2000_write(priv, ret = regmap_write(priv->regmap,
Ratio_Add(ch, i), Ratio_Add(ch, i),
Ratio_Val(val, i)); Ratio_Val(val, i));
if (ret < 0) if (ret < 0)
@ -247,14 +254,14 @@ static int cs2000_ratio_set(struct cs2000_priv *priv,
static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch) static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch)
{ {
s32 tmp; unsigned int tmp, i;
u32 val; u32 val;
unsigned int i; int ret;
val = 0; val = 0;
for (i = 0; i < RATIO_REG_SIZE; i++) { for (i = 0; i < RATIO_REG_SIZE; i++) {
tmp = cs2000_read(priv, Ratio_Add(ch, i)); ret = regmap_read(priv->regmap, Ratio_Add(ch, i), &tmp);
if (tmp < 0) if (ret < 0)
return 0; return 0;
val |= Val_Ratio(tmp, i); val |= Val_Ratio(tmp, i);
@ -271,15 +278,15 @@ static int cs2000_ratio_select(struct cs2000_priv *priv, int ch)
if (CH_SIZE_ERR(ch)) if (CH_SIZE_ERR(ch))
return -EINVAL; return -EINVAL;
ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch)); ret = regmap_update_bits(priv->regmap, DEVICE_CFG1, RSEL_MASK, RSEL(ch));
if (ret < 0) if (ret < 0)
return ret; return ret;
fracnsrc = priv->dynamic_mode ? FRACNSRC_DYNAMIC : FRACNSRC_STATIC; fracnsrc = priv->dynamic_mode ? FRACNSRC_DYNAMIC : FRACNSRC_STATIC;
ret = cs2000_bset(priv, DEVICE_CFG2, ret = regmap_update_bits(priv->regmap, DEVICE_CFG2,
AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK, AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK,
LOCKCLK(ch) | fracnsrc); LOCKCLK(ch) | fracnsrc);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -326,8 +333,8 @@ static int cs2000_select_ratio_mode(struct cs2000_priv *priv,
*/ */
priv->lf_ratio = priv->dynamic_mode && ((rate / parent_rate) > 4096); priv->lf_ratio = priv->dynamic_mode && ((rate / parent_rate) > 4096);
return cs2000_bset(priv, FUNC_CFG2, LFRATIO_MASK, return regmap_update_bits(priv->regmap, FUNC_CFG2, LFRATIO_MASK,
priv->lf_ratio ? LFRATIO_20_12 : LFRATIO_12_20); priv->lf_ratio ? LFRATIO_20_12 : LFRATIO_12_20);
} }
static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
@ -336,7 +343,7 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
{ {
int ret; int ret;
ret = cs2000_bset(priv, GLOBAL_CFG, FREEZE, FREEZE); ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, FREEZE, FREEZE);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -352,7 +359,7 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = cs2000_bset(priv, GLOBAL_CFG, FREEZE, 0); ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, FREEZE, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -469,8 +476,8 @@ static int cs2000_clk_register(struct cs2000_priv *priv)
priv->dynamic_mode ? "dynamic" : "static"); priv->dynamic_mode ? "dynamic" : "static");
of_property_read_u32(np, "cirrus,aux-output-source", &aux_out); of_property_read_u32(np, "cirrus,aux-output-source", &aux_out);
ret = cs2000_bset(priv, DEVICE_CFG1, ret = regmap_update_bits(priv->regmap, DEVICE_CFG1,
AUXOUTSRC_MASK, AUXOUTSRC(aux_out)); AUXOUTSRC_MASK, AUXOUTSRC(aux_out));
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -522,12 +529,13 @@ static int cs2000_clk_register(struct cs2000_priv *priv)
static int cs2000_version_print(struct cs2000_priv *priv) static int cs2000_version_print(struct cs2000_priv *priv)
{ {
struct device *dev = priv_to_dev(priv); struct device *dev = priv_to_dev(priv);
s32 val;
const char *revision; const char *revision;
unsigned int val;
int ret;
val = cs2000_read(priv, DEVICE_ID); ret = regmap_read(priv->regmap, DEVICE_ID, &val);
if (val < 0) if (ret < 0)
return val; return ret;
/* CS2000 should be 0x0 */ /* CS2000 should be 0x0 */
if (val >> 3) if (val >> 3)
@ -576,6 +584,10 @@ static int cs2000_probe(struct i2c_client *client,
priv->client = client; priv->client = client;
i2c_set_clientdata(client, priv); i2c_set_clientdata(client, priv);
priv->regmap = devm_regmap_init_i2c(client, &cs2000_regmap_config);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
ret = cs2000_clk_get(priv); ret = cs2000_clk_get(priv);
if (ret < 0) if (ret < 0)
return ret; return ret;