diff options
Diffstat (limited to 'drivers/clk/clk-lmk04832.c')
| -rw-r--r-- | drivers/clk/clk-lmk04832.c | 188 |
1 files changed, 85 insertions, 103 deletions
diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c index c7a3a029fb1e..b2107b31efa2 100644 --- a/drivers/clk/clk-lmk04832.c +++ b/drivers/clk/clk-lmk04832.c @@ -12,12 +12,10 @@ #include <linux/bitfield.h> #include <linux/clk.h> #include <linux/clk-provider.h> -#include <linux/debugfs.h> #include <linux/device.h> #include <linux/gcd.h> #include <linux/gpio/consumer.h> #include <linux/module.h> -#include <linux/uaccess.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -136,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 @@ -177,14 +180,14 @@ enum lmk04832_device_types { }; /** - * lmk04832_device_info - Holds static device information that is specific to - * the chip revision + * struct lmk04832_device_info - Holds static device information that is + * specific to the chip revision * - * pid: Product Identifier - * maskrev: IC version identifier - * num_channels: Number of available output channels (clkout count) - * vco0_range: {min, max} of the VCO0 operating range (in MHz) - * vco1_range: {min, max} of the VCO1 operating range (in MHz) + * @pid: Product Identifier + * @maskrev: IC version identifier + * @num_channels: Number of available output channels (clkout count) + * @vco0_range: {min, max} of the VCO0 operating range (in MHz) + * @vco1_range: {min, max} of the VCO1 operating range (in MHz) */ struct lmk04832_device_info { u16 pid; @@ -208,6 +211,7 @@ enum lmk04832_rdbk_type { RDBK_CLKIN_SEL0, RDBK_CLKIN_SEL1, RDBK_RESET, + RDBK_PLL1_LD, }; struct lmk_dclk { @@ -269,61 +273,43 @@ static bool lmk04832_regmap_rd_regs(struct device *dev, unsigned int reg) { switch (reg) { case LMK04832_REG_RST3W ... LMK04832_REG_ID_MASKREV: - fallthrough; case LMK04832_REG_ID_VNDR_MSB: - fallthrough; case LMK04832_REG_ID_VNDR_LSB: - fallthrough; case LMK04832_REG_CLKOUT_CTRL0(0) ... LMK04832_REG_PLL2_DLD_CNT_LSB: - fallthrough; case LMK04832_REG_PLL2_LD: - fallthrough; case LMK04832_REG_PLL2_PD: - fallthrough; case LMK04832_REG_PLL1R_RST: - fallthrough; case LMK04832_REG_CLR_PLL_LOST ... LMK04832_REG_RB_DAC_VAL_LSB: - fallthrough; case LMK04832_REG_RB_HOLDOVER: - fallthrough; case LMK04832_REG_SPI_LOCK: return true; default: return false; }; -}; +} static bool lmk04832_regmap_wr_regs(struct device *dev, unsigned int reg) { switch (reg) { case LMK04832_REG_RST3W: - fallthrough; case LMK04832_REG_POWERDOWN: return true; case LMK04832_REG_ID_DEV_TYPE ... LMK04832_REG_ID_MASKREV: - fallthrough; case LMK04832_REG_ID_VNDR_MSB: - fallthrough; case LMK04832_REG_ID_VNDR_LSB: return false; case LMK04832_REG_CLKOUT_CTRL0(0) ... LMK04832_REG_PLL2_DLD_CNT_LSB: - fallthrough; case LMK04832_REG_PLL2_LD: - fallthrough; case LMK04832_REG_PLL2_PD: - fallthrough; case LMK04832_REG_PLL1R_RST: - fallthrough; case LMK04832_REG_CLR_PLL_LOST ... LMK04832_REG_RB_DAC_VAL_LSB: - fallthrough; case LMK04832_REG_RB_HOLDOVER: - fallthrough; case LMK04832_REG_SPI_LOCK: return true; default: return false; }; -}; +} static const struct regmap_config regmap_config = { .name = "lmk04832", @@ -389,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); - 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; @@ -421,7 +407,7 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw, pll2_misc)) * pll2_n * pll2_p[p] / pll2_r; return vco_rate; -}; +} /** * lmk04832_check_vco_ranges - Check requested VCO frequency against VCO ranges @@ -432,7 +418,7 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw, * The LMK04832 has 2 internal VCO, each with independent operating ranges. * Use the device_info structure to determine which VCO to use based on rate. * - * Returns VCO_MUX value or negative errno. + * Returns: VCO_MUX value or negative errno. */ static int lmk04832_check_vco_ranges(struct lmk04832 *lmk, unsigned long rate) { @@ -469,7 +455,7 @@ static int lmk04832_check_vco_ranges(struct lmk04832 *lmk, unsigned long rate) * * VCO = OSCin * 2 * PLL2_N * PLL2_P / PLL2_R * - * Returns vco rate or negative errno. + * Returns: vco rate or negative errno. */ static long lmk04832_calc_pll2_params(unsigned long prate, unsigned long rate, unsigned int *n, unsigned int *p, @@ -505,29 +491,34 @@ 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, unsigned long prate) @@ -586,14 +577,14 @@ static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate, return regmap_write(lmk->regmap, LMK04832_REG_PLL2_N_2, FIELD_GET(0x0000ff, n)); -}; +} static const struct clk_ops lmk04832_vco_ops = { .is_enabled = lmk04832_vco_is_enabled, .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, }; @@ -651,7 +642,7 @@ static int lmk04832_register_vco(struct lmk04832 *lmk) static int lmk04832_clkout_set_ddly(struct lmk04832 *lmk, int id) { - 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; @@ -902,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, @@ -959,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, }; @@ -1081,29 +1074,31 @@ static unsigned long lmk04832_dclk_recalc_rate(struct clk_hw *hw, rate = DIV_ROUND_CLOSEST(prate, dclk_div); 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, unsigned long prate) @@ -1165,14 +1160,14 @@ static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate, dev_err(lmk->dev, "SYNC sequence failed\n"); return ret; -}; +} static const struct clk_ops lmk04832_dclk_ops = { .is_enabled = lmk04832_dclk_is_enabled, .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, }; @@ -1299,6 +1294,7 @@ static const struct clk_ops lmk04832_clkout_ops = { .is_enabled = lmk04832_clkout_is_enabled, .prepare = lmk04832_clkout_prepare, .unprepare = lmk04832_clkout_unprepare, + .determine_rate = __clk_mux_determine_rate, .set_parent = lmk04832_clkout_set_parent, .get_parent = lmk04832_clkout_get_parent, }; @@ -1316,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; @@ -1364,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, @@ -1381,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) @@ -1410,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); @@ -1427,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, @@ -1442,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); @@ -1470,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", @@ -1491,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); @@ -1501,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); @@ -1509,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) { @@ -1523,54 +1523,37 @@ 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; } } lmk->clk_data->num = info->num_channels; - ret = of_clk_add_hw_provider(lmk->dev->of_node, of_clk_hw_onecell_get, - lmk->clk_data); + ret = devm_of_clk_add_hw_provider(lmk->dev, of_clk_hw_onecell_get, + 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 int lmk04832_remove(struct spi_device *spi) -{ - struct lmk04832 *lmk = spi_get_drvdata(spi); - - clk_disable_unprepare(lmk->oscin); - of_clk_del_provider(spi->dev.of_node); - - return 0; -} static const struct spi_device_id lmk04832_id[] = { { "lmk04832", LMK04832 }, {} @@ -1589,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); |
