diff options
Diffstat (limited to 'drivers/clk/clk-lmk04832.c')
| -rw-r--r-- | drivers/clk/clk-lmk04832.c | 127 |
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); |
