summaryrefslogtreecommitdiff
path: root/drivers/clk/clk-lmk04832.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/clk-lmk04832.c')
-rw-r--r--drivers/clk/clk-lmk04832.c127
1 files changed, 65 insertions, 62 deletions
diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c
index e22ac93e0c2f..b2107b31efa2 100644
--- a/drivers/clk/clk-lmk04832.c
+++ b/drivers/clk/clk-lmk04832.c
@@ -134,6 +134,11 @@
/* 0x14b - 0x152 Holdover */
/* 0x153 - 0x15f PLL1 Configuration */
+#define LMK04832_REG_PLL1_LD 0x15f
+#define LMK04832_BIT_PLL1_LD_MUX GENMASK(7, 3)
+#define LMK04832_VAL_PLL1_LD_MUX_SPI_RDBK 0x07
+#define LMK04832_BIT_PLL1_LD_TYPE GENMASK(2, 0)
+#define LMK04832_VAL_PLL1_LD_TYPE_OUT_PP 0x03
/* 0x160 - 0x16e PLL2 Configuration */
#define LMK04832_REG_PLL2_R_MSB 0x160
@@ -206,6 +211,7 @@ enum lmk04832_rdbk_type {
RDBK_CLKIN_SEL0,
RDBK_CLKIN_SEL1,
RDBK_RESET,
+ RDBK_PLL1_LD,
};
struct lmk_dclk {
@@ -369,7 +375,7 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
- const unsigned int pll2_p[] = {8, 2, 2, 3, 4, 5, 6, 7};
+ static const unsigned int pll2_p[] = {8, 2, 2, 3, 4, 5, 6, 7};
unsigned int pll2_n, p, pll2_r;
unsigned int pll2_misc;
unsigned long vco_rate;
@@ -485,28 +491,33 @@ static long lmk04832_calc_pll2_params(unsigned long prate, unsigned long rate,
return DIV_ROUND_CLOSEST(prate * 2 * pll2_p * pll2_n, pll2_r);
}
-static long lmk04832_vco_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int lmk04832_vco_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
unsigned int n, p, r;
long vco_rate;
int ret;
- ret = lmk04832_check_vco_ranges(lmk, rate);
+ ret = lmk04832_check_vco_ranges(lmk, req->rate);
if (ret < 0)
return ret;
- vco_rate = lmk04832_calc_pll2_params(*prate, rate, &n, &p, &r);
+ vco_rate = lmk04832_calc_pll2_params(req->best_parent_rate, req->rate,
+ &n, &p, &r);
if (vco_rate < 0) {
dev_err(lmk->dev, "PLL2 parameters out of range\n");
- return vco_rate;
+ req->rate = vco_rate;
+
+ return 0;
}
- if (rate != vco_rate)
+ if (req->rate != vco_rate)
return -EINVAL;
- return vco_rate;
+ req->rate = vco_rate;
+
+ return 0;
}
static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -573,7 +584,7 @@ static const struct clk_ops lmk04832_vco_ops = {
.prepare = lmk04832_vco_prepare,
.unprepare = lmk04832_vco_unprepare,
.recalc_rate = lmk04832_vco_recalc_rate,
- .round_rate = lmk04832_vco_round_rate,
+ .determine_rate = lmk04832_vco_determine_rate,
.set_rate = lmk04832_vco_set_rate,
};
@@ -631,7 +642,7 @@ static int lmk04832_register_vco(struct lmk04832 *lmk)
static int lmk04832_clkout_set_ddly(struct lmk04832 *lmk, int id)
{
- const int dclk_div_adj[] = {0, 0, -2, -2, 0, 3, -1, 0};
+ static const int dclk_div_adj[] = {0, 0, -2, -2, 0, 3, -1, 0};
unsigned int sclkx_y_ddly = 10;
unsigned int dclkx_y_ddly;
unsigned int dclkx_y_div;
@@ -882,25 +893,27 @@ static unsigned long lmk04832_sclk_recalc_rate(struct clk_hw *hw,
return DIV_ROUND_CLOSEST(prate, sysref_div);
}
-static long lmk04832_sclk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int lmk04832_sclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct lmk04832 *lmk = container_of(hw, struct lmk04832, sclk);
unsigned long sclk_rate;
unsigned int sysref_div;
- sysref_div = DIV_ROUND_CLOSEST(*prate, rate);
- sclk_rate = DIV_ROUND_CLOSEST(*prate, sysref_div);
+ sysref_div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
+ sclk_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, sysref_div);
if (sysref_div < 0x07 || sysref_div > 0x1fff) {
dev_err(lmk->dev, "SYSREF divider out of range\n");
return -EINVAL;
}
- if (rate != sclk_rate)
+ if (req->rate != sclk_rate)
return -EINVAL;
- return sclk_rate;
+ req->rate = sclk_rate;
+
+ return 0;
}
static int lmk04832_sclk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -939,7 +952,7 @@ static const struct clk_ops lmk04832_sclk_ops = {
.prepare = lmk04832_sclk_prepare,
.unprepare = lmk04832_sclk_unprepare,
.recalc_rate = lmk04832_sclk_recalc_rate,
- .round_rate = lmk04832_sclk_round_rate,
+ .determine_rate = lmk04832_sclk_determine_rate,
.set_rate = lmk04832_sclk_set_rate,
};
@@ -1063,26 +1076,28 @@ static unsigned long lmk04832_dclk_recalc_rate(struct clk_hw *hw,
return rate;
}
-static long lmk04832_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int lmk04832_dclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct lmk_dclk *dclk = container_of(hw, struct lmk_dclk, hw);
struct lmk04832 *lmk = dclk->lmk;
unsigned long dclk_rate;
unsigned int dclk_div;
- dclk_div = DIV_ROUND_CLOSEST(*prate, rate);
- dclk_rate = DIV_ROUND_CLOSEST(*prate, dclk_div);
+ dclk_div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
+ dclk_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, dclk_div);
if (dclk_div < 1 || dclk_div > 0x3ff) {
dev_err(lmk->dev, "%s_div out of range\n", clk_hw_get_name(hw));
return -EINVAL;
}
- if (rate != dclk_rate)
+ if (req->rate != dclk_rate)
return -EINVAL;
- return dclk_rate;
+ req->rate = dclk_rate;
+
+ return 0;
}
static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -1152,7 +1167,7 @@ static const struct clk_ops lmk04832_dclk_ops = {
.prepare = lmk04832_dclk_prepare,
.unprepare = lmk04832_dclk_unprepare,
.recalc_rate = lmk04832_dclk_recalc_rate,
- .round_rate = lmk04832_dclk_round_rate,
+ .determine_rate = lmk04832_dclk_determine_rate,
.set_rate = lmk04832_dclk_set_rate,
};
@@ -1297,6 +1312,7 @@ static int lmk04832_register_clkout(struct lmk04832 *lmk, const int num)
sprintf(dclk_name, "lmk-dclk%02d_%02d", num, num + 1);
init.name = dclk_name;
parent_names[0] = clk_hw_get_name(&lmk->vco);
+ init.parent_names = parent_names;
init.ops = &lmk04832_dclk_ops;
init.flags = CLK_SET_RATE_PARENT;
init.num_parents = 1;
@@ -1345,6 +1361,10 @@ static int lmk04832_set_spi_rdbk(const struct lmk04832 *lmk, const int rdbk_pin)
{
int reg;
int ret;
+ int val = FIELD_PREP(LMK04832_BIT_CLKIN_SEL_MUX,
+ LMK04832_VAL_CLKIN_SEL_MUX_SPI_RDBK) |
+ FIELD_PREP(LMK04832_BIT_CLKIN_SEL_TYPE,
+ LMK04832_VAL_CLKIN_SEL_TYPE_OUT);
dev_info(lmk->dev, "setting up 4-wire mode\n");
ret = regmap_write(lmk->regmap, LMK04832_REG_RST3W,
@@ -1362,15 +1382,18 @@ static int lmk04832_set_spi_rdbk(const struct lmk04832 *lmk, const int rdbk_pin)
case RDBK_RESET:
reg = LMK04832_REG_CLKIN_RST;
break;
+ case RDBK_PLL1_LD:
+ reg = LMK04832_REG_PLL1_LD;
+ val = FIELD_PREP(LMK04832_BIT_PLL1_LD_MUX,
+ LMK04832_VAL_PLL1_LD_MUX_SPI_RDBK) |
+ FIELD_PREP(LMK04832_BIT_PLL1_LD_TYPE,
+ LMK04832_VAL_PLL1_LD_TYPE_OUT_PP);
+ break;
default:
return -EINVAL;
}
- return regmap_write(lmk->regmap, reg,
- FIELD_PREP(LMK04832_BIT_CLKIN_SEL_MUX,
- LMK04832_VAL_CLKIN_SEL_MUX_SPI_RDBK) |
- FIELD_PREP(LMK04832_BIT_CLKIN_SEL_TYPE,
- LMK04832_VAL_CLKIN_SEL_TYPE_OUT));
+ return regmap_write(lmk->regmap, reg, val);
}
static int lmk04832_probe(struct spi_device *spi)
@@ -1391,16 +1414,12 @@ static int lmk04832_probe(struct spi_device *spi)
lmk->dev = &spi->dev;
- lmk->oscin = devm_clk_get(lmk->dev, "oscin");
+ lmk->oscin = devm_clk_get_enabled(lmk->dev, "oscin");
if (IS_ERR(lmk->oscin)) {
dev_err(lmk->dev, "failed to get oscin clock\n");
return PTR_ERR(lmk->oscin);
}
- ret = clk_prepare_enable(lmk->oscin);
- if (ret)
- return ret;
-
lmk->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
GPIOD_OUT_LOW);
@@ -1408,14 +1427,14 @@ static int lmk04832_probe(struct spi_device *spi)
sizeof(struct lmk_dclk), GFP_KERNEL);
if (!lmk->dclk) {
ret = -ENOMEM;
- goto err_disable_oscin;
+ return ret;
}
lmk->clkout = devm_kcalloc(lmk->dev, info->num_channels,
sizeof(*lmk->clkout), GFP_KERNEL);
if (!lmk->clkout) {
ret = -ENOMEM;
- goto err_disable_oscin;
+ return ret;
}
lmk->clk_data = devm_kzalloc(lmk->dev, struct_size(lmk->clk_data, hws,
@@ -1423,7 +1442,7 @@ static int lmk04832_probe(struct spi_device *spi)
GFP_KERNEL);
if (!lmk->clk_data) {
ret = -ENOMEM;
- goto err_disable_oscin;
+ return ret;
}
device_property_read_u32(lmk->dev, "ti,vco-hz", &lmk->vco_rate);
@@ -1451,7 +1470,7 @@ static int lmk04832_probe(struct spi_device *spi)
dev_err(lmk->dev, "missing reg property in child: %s\n",
child->full_name);
of_node_put(child);
- goto err_disable_oscin;
+ return ret;
}
of_property_read_u32(child, "ti,clkout-fmt",
@@ -1472,7 +1491,7 @@ static int lmk04832_probe(struct spi_device *spi)
__func__, PTR_ERR(lmk->regmap));
ret = PTR_ERR(lmk->regmap);
- goto err_disable_oscin;
+ return ret;
}
regmap_write(lmk->regmap, LMK04832_REG_RST3W, LMK04832_BIT_RESET);
@@ -1482,7 +1501,7 @@ static int lmk04832_probe(struct spi_device *spi)
&rdbk_pin);
ret = lmk04832_set_spi_rdbk(lmk, rdbk_pin);
if (ret)
- goto err_disable_oscin;
+ return ret;
}
regmap_bulk_read(lmk->regmap, LMK04832_REG_ID_PROD_MSB, &tmp, 3);
@@ -1490,13 +1509,13 @@ static int lmk04832_probe(struct spi_device *spi)
dev_err(lmk->dev, "unsupported device type: pid 0x%04x, maskrev 0x%02x\n",
tmp[0] << 8 | tmp[1], tmp[2]);
ret = -EINVAL;
- goto err_disable_oscin;
+ return ret;
}
ret = lmk04832_register_vco(lmk);
if (ret) {
dev_err(lmk->dev, "failed to init device clock path\n");
- goto err_disable_oscin;
+ return ret;
}
if (lmk->vco_rate) {
@@ -1504,21 +1523,21 @@ static int lmk04832_probe(struct spi_device *spi)
ret = clk_set_rate(lmk->vco.clk, lmk->vco_rate);
if (ret) {
dev_err(lmk->dev, "failed to set VCO rate\n");
- goto err_disable_vco;
+ return ret;
}
}
ret = lmk04832_register_sclk(lmk);
if (ret) {
dev_err(lmk->dev, "failed to init SYNC/SYSREF clock path\n");
- goto err_disable_vco;
+ return ret;
}
for (i = 0; i < info->num_channels; i++) {
ret = lmk04832_register_clkout(lmk, i);
if (ret) {
dev_err(lmk->dev, "failed to register clk %d\n", i);
- goto err_disable_vco;
+ return ret;
}
}
@@ -1527,27 +1546,12 @@ static int lmk04832_probe(struct spi_device *spi)
lmk->clk_data);
if (ret) {
dev_err(lmk->dev, "failed to add provider (%d)\n", ret);
- goto err_disable_vco;
+ return ret;
}
spi_set_drvdata(spi, lmk);
return 0;
-
-err_disable_vco:
- clk_disable_unprepare(lmk->vco.clk);
-
-err_disable_oscin:
- clk_disable_unprepare(lmk->oscin);
-
- return ret;
-}
-
-static void lmk04832_remove(struct spi_device *spi)
-{
- struct lmk04832 *lmk = spi_get_drvdata(spi);
-
- clk_disable_unprepare(lmk->oscin);
}
static const struct spi_device_id lmk04832_id[] = {
@@ -1568,7 +1572,6 @@ static struct spi_driver lmk04832_driver = {
.of_match_table = lmk04832_of_id,
},
.probe = lmk04832_probe,
- .remove = lmk04832_remove,
.id_table = lmk04832_id,
};
module_spi_driver(lmk04832_driver);