// SPDX-License-Identifier: GPL-2.0 /* * Driver for Silicon Labs Si5340, Si5341, Si5342, Si5344 and Si5345 * Copyright (C) 2019 Topic Embedded Products * Author: Mike Looijmans <mike.looijmans@topic.nl> * * The Si5341 has 10 outputs and 5 synthesizers. * The Si5340 is a smaller version of the Si5341 with only 4 outputs. * The Si5345 is similar to the Si5341, with the addition of fractional input * dividers and automatic input selection. * The Si5342 and Si5344 are smaller versions of the Si5345.
*/
/* Read and interpret a 44-bit followed by a 32-bit value in the regmap */ staticint si5341_decode_44_32(struct regmap *regmap, unsignedint reg,
u64 *val1, u32 *val2)
{ int err;
u8 r[10];
/* Program the fraction */ return regmap_bulk_write(regmap, reg, r, sizeof(r));
}
/* VCO, we assume it runs at a constant frequency */ staticunsignedlong si5341_clk_recalc_rate(struct clk_hw *hw, unsignedlong parent_rate)
{ struct clk_si5341 *data = to_clk_si5341(hw); int err;
u64 res;
u64 m_num;
u32 m_den; unsignedint shift;
/* Assume that PDIV is not being used, just read the PLL setting */
err = si5341_decode_44_32(data->regmap, SI5341_PLL_M_NUM,
&m_num, &m_den); if (err < 0) return 0;
if (!m_num || !m_den) return 0;
/* * Though m_num is 64-bit, only the upper bits are actually used. While * calculating m_num and m_den, they are shifted as far as possible to * the left. To avoid 96-bit division here, we just shift them back so * we can do with just 64 bits.
*/
shift = 0;
res = m_num; while (res & 0xffff00000000ULL) {
++shift;
res >>= 1;
}
res *= parent_rate;
do_div(res, (m_den >> shift));
/* We cannot return the actual frequency in 32 bit, store it locally */
data->freq_vco = res;
/* Report kHz since the value is out of range */
do_div(res, 1000);
return (unsignedlong)res;
}
staticint si5341_clk_get_selected_input(struct clk_si5341 *data)
{ int err;
u32 val;
if (index < 3) { /* Enable input buffer for selected input */
err = regmap_update_bits(data->regmap,
SI5341_IN_EN, 0x07, BIT(index)); if (err < 0) return err;
/* Enables the input to phase detector */
err = regmap_update_bits(data->regmap, SI5341_INX_TO_PFD_EN,
0x7 << SI5341_INX_TO_PFD_SHIFT,
BIT(index + SI5341_INX_TO_PFD_SHIFT)); if (err < 0) return err;
/* Power down XTAL oscillator and buffer */
err = regmap_update_bits(data->regmap, SI5341_XAXB_CFG,
SI5341_XAXB_CFG_PDNB, 0); if (err < 0) return err;
/* * Set the P divider to "1". There's no explanation in the * datasheet of these registers, but the clockbuilder software * programs a "1" when the input is being used.
*/
err = regmap_write(data->regmap, SI5341_IN_PDIV(index), 1); if (err < 0) return err;
/* Synthesizers, there are 5 synthesizers that connect to any of the outputs */
/* The synthesizer is on if all power and enable bits are set */ staticint si5341_synth_clk_is_on(struct clk_hw *hw)
{ struct clk_si5341_synth *synth = to_clk_si5341_synth(hw); int err;
u32 val;
u8 index = synth->index;
/* This bit must be 0 for the synthesizer to receive clock input */
err = regmap_read(synth->data->regmap, SI5341_SYNTH_N_CLK_DIS, &val); if (err < 0) return 0;
return !(val & BIT(index));
}
staticvoid si5341_synth_clk_unprepare(struct clk_hw *hw)
{ struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
u8 index = synth->index; /* In range 0..5 */
u8 mask = BIT(index);
/* Disable output */
regmap_update_bits(synth->data->regmap,
SI5341_SYNTH_N_CLK_TO_OUTX_EN, mask, 0); /* Power down */
regmap_update_bits(synth->data->regmap,
SI5341_SYNTH_N_PDNB, mask, 0); /* Disable clock input to synth (set to 1 to disable) */
regmap_update_bits(synth->data->regmap,
SI5341_SYNTH_N_CLK_DIS, mask, mask);
}
staticint si5341_synth_clk_prepare(struct clk_hw *hw)
{ struct clk_si5341_synth *synth = to_clk_si5341_synth(hw); int err;
u8 index = synth->index;
u8 mask = BIT(index);
/* Power up */
err = regmap_update_bits(synth->data->regmap,
SI5341_SYNTH_N_PDNB, mask, mask); if (err < 0) return err;
/* Enable clock input to synth (set bit to 0 to enable) */
err = regmap_update_bits(synth->data->regmap,
SI5341_SYNTH_N_CLK_DIS, mask, 0); if (err < 0) return err;
err = si5341_decode_44_32(synth->data->regmap,
SI5341_SYNTH_N_NUM(synth->index), &n_num, &n_den); if (err < 0) return err; /* Check for bogus/uninitialized settings */ if (!n_num || !n_den) return 0;
/* * n_num and n_den are shifted left as much as possible, so to prevent * overflow in 64-bit math, we shift n_den 4 bits to the right
*/
f = synth->data->freq_vco;
f *= n_den >> 4;
/* Now we need to do 64-bit division: f/n_num */ /* And compensate for the 4 bits we dropped */
f = div64_u64(f, (n_num >> 4));
/* The synthesizer accuracy is such that anything in range will work */
f = synth->data->freq_vco;
do_div(f, SI5341_SYNTH_N_MAX); if (rate < f) return f;
f = synth->data->freq_vco;
do_div(f, SI5341_SYNTH_N_MIN); if (rate > f) return f;
return rate;
}
staticint si5341_synth_program(struct clk_si5341_synth *synth,
u64 n_num, u32 n_den, bool is_integer)
{ int err;
u8 index = synth->index;
/* Bit 0=PDN, 1=OE so only a value of 0x2 enables the output */ return (val & 0x03) == SI5341_OUT_CFG_OE;
}
/* Disables and then powers down the output */ staticvoid si5341_output_clk_unprepare(struct clk_hw *hw)
{ struct clk_si5341_output *output = to_clk_si5341_output(hw);
/* Powers up and then enables the output */ staticint si5341_output_clk_prepare(struct clk_hw *hw)
{ struct clk_si5341_output *output = to_clk_si5341_output(hw); int err;
/* If rate is an even divisor, no changes to parent required */ if (r && !(r % rate)) return 0;
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { if (rate > 200000000) { /* minimum r-divider is 2 */
r = 2;
} else { /* Take a parent frequency near 400 MHz */
r = (400000000u / rate) & ~1;
}
req->best_parent_rate = r * rate;
} else { /* We cannot change our parent's rate, report what we can do */
r /= rate;
rate = req->best_parent_rate / (r << 1);
}
/* For a value of "2", we set the "OUT0_RDIV_FORCE2" bit */
err = regmap_update_bits(output->data->regmap,
SI5341_OUT_CONFIG(output),
SI5341_OUT_CFG_RDIV_FORCE2,
(r_div == 0) ? SI5341_OUT_CFG_RDIV_FORCE2 : 0); if (err < 0) return err;
/* Always write Rx_REG, because a zero value disables the divider */
r[0] = r_div ? (r_div & 0xff) : 1;
r[1] = (r_div >> 8) & 0xff;
r[2] = (r_div >> 16) & 0xff; return regmap_bulk_write(output->data->regmap,
SI5341_OUT_R_REG(output), r, 3);
}
/* * The chip can be bought in a pre-programmed version, or one can program the * NVM in the chip to boot up in a preset mode. This routine tries to determine * if that's the case, or if we need to reset and program everything from * scratch. Returns negative error, or true/false.
*/ staticint si5341_is_programmed_already(struct clk_si5341 *data)
{ int err;
u8 r[4];
/* Read the PLL divider value, it must have a non-zero value */
err = regmap_bulk_read(data->regmap, SI5341_PLL_M_DEN,
r, ARRAY_SIZE(r)); if (err < 0) return err;
/* Read active settings into the regmap cache for later reference */ staticint si5341_read_settings(struct clk_si5341 *data)
{ int err;
u8 i;
u8 r[10];
for (i = 0; i < num_values; ++i) {
res = regmap_write(data->regmap,
values[i].address, values[i].value); if (res < 0) {
dev_err(&data->i2c_client->dev, "Failed to write %#x:%#x\n",
values[i].address, values[i].value); return res;
}
}
staticint si5341_send_preamble(struct clk_si5341 *data)
{ int res;
u32 revision;
/* For revision 2 and up, the values are slightly different */
res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision); if (res < 0) return res;
/* Write "preamble" as specified by datasheet */
res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xD8 : 0xC0); if (res < 0) return res;
/* The si5342..si5345 require a different preamble */ if (data->chip_id > 0x5341)
res = si5341_write_multiple(data,
si5345_preamble, ARRAY_SIZE(si5345_preamble)); else
res = si5341_write_multiple(data,
si5341_preamble, ARRAY_SIZE(si5341_preamble)); if (res < 0) return res;
/* Datasheet specifies a 300ms wait after sending the preamble */
msleep(300);
return 0;
}
/* Perform a soft reset and write post-amble */ staticint si5341_finalize_defaults(struct clk_si5341 *data)
{ int res;
u32 revision;
res = regmap_write(data->regmap, SI5341_IO_VDD_SEL,
data->iovdd_33 ? 1 : 0); if (res < 0) return res;
res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision); if (res < 0) return res;
res = regmap_write(data->regmap, SI5341_SOFT_RST, 0x01); if (res < 0) return res;
/* The si5342..si5345 have an additional post-amble */ if (data->chip_id > 0x5341) {
res = regmap_write(data->regmap, 0x540, 0x0); if (res < 0) return res;
}
/* Datasheet does not explain these nameless registers */
res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xDB : 0xC3); if (res < 0) return res;
res = regmap_write(data->regmap, 0x0B25, 0x02); if (res < 0) return res;
/* Pages 0, 1, 2, 3, 9, A, B are valid, so there are 12 pages */ staticconststruct regmap_range_cfg si5341_regmap_ranges[] = {
{
.range_min = 0,
.range_max = SI5341_REGISTER_MAX,
.selector_reg = SI5341_PAGE,
.selector_mask = 0xff,
.selector_shift = 0,
.window_start = 0,
.window_len = 256,
},
};
staticint si5341_wait_device_ready(struct i2c_client *client)
{ int count;
/* Datasheet warns: Any attempt to read or write any register other * than DEVICE_READY before DEVICE_READY reads as 0x0F may corrupt the * NVM programming and may corrupt the register contents, as they are * read from NVM. Note that this includes accesses to the PAGE register. * Also: DEVICE_READY is available on every register page, so no page * change is needed to read it. * Do this outside regmap to avoid automatic PAGE register access. * May take up to 300ms to complete.
*/ for (count = 0; count < 15; ++count) {
s32 result = i2c_smbus_read_byte_data(client,
SI5341_DEVICE_READY); if (result < 0) return result; if (result == 0x0F) return 0;
msleep(20);
}
dev_err(&client->dev, "timeout waiting for DEVICE_READY\n"); return -EIO;
}
config[num].vdd_sel_bits = 0x08; if (data->clk[num].vddo_reg) { int vdd = regulator_get_voltage(data->clk[num].vddo_reg);
switch (vdd) { case 3300000:
config[num].vdd_sel_bits |= 0 << 4; break; case 1800000:
config[num].vdd_sel_bits |= 1 << 4; break; case 2500000:
config[num].vdd_sel_bits |= 2 << 4; break; default:
dev_err(&data->i2c_client->dev, "unsupported vddo voltage %d for %s\n",
vdd, child->name); goto put_child;
}
} else { /* chip seems to default to 2.5V when not set */
dev_warn(&data->i2c_client->dev, "no regulator set, defaulting vdd_sel to 2.5V for %s\n",
child->name);
config[num].vdd_sel_bits |= 2 << 4;
}
}
return 0;
put_child:
of_node_put(child); return -EINVAL;
}
/* * If not pre-configured, calculate and set the PLL configuration manually. * For low-jitter performance, the PLL should be set such that the synthesizers * only need integer division. * Without any user guidance, we'll set the PLL to 14GHz, which still allows * the chip to generate any frequency on its outputs, but jitter performance * may be sub-optimal.
*/ staticint si5341_initialize_pll(struct clk_si5341 *data)
{ struct device_node *np = data->i2c_client->dev.of_node;
u32 m_num = 0;
u32 m_den = 0; int sel;
staticint si5341_clk_select_active_input(struct clk_si5341 *data)
{ int res; int err; int i;
res = si5341_clk_get_selected_input(data); if (res < 0) return res;
/* If the current register setting is invalid, pick the first input */ if (!data->input_clk[res]) {
dev_dbg(&data->i2c_client->dev, "Input %d not connected, rerouting\n", res);
res = -ENODEV; for (i = 0; i < SI5341_NUM_INPUTS; ++i) { if (data->input_clk[i]) {
res = i; break;
}
} if (res < 0) {
dev_err(&data->i2c_client->dev, "No clock input available\n"); return res;
}
}
/* Make sure the selected clock is also enabled and routed */
err = si5341_clk_reparent(data, res); if (err < 0) return err;
err = clk_prepare_enable(data->input_clk[res]); if (err < 0) return err;
if (initialization_required) { /* Populate the regmap cache in preparation for "cache only" */
err = si5341_read_settings(data); if (err < 0) goto cleanup;
err = si5341_send_preamble(data); if (err < 0) goto cleanup;
/* * We intend to send all 'final' register values in a single * transaction. So cache all register writes until we're done * configuring.
*/
regcache_cache_only(data->regmap, true);
/* Write the configuration pairs from the firmware blob */
err = si5341_write_multiple(data, si5341_reg_defaults,
ARRAY_SIZE(si5341_reg_defaults)); if (err < 0) goto cleanup;
}
/* Input must be up and running at this point */
err = si5341_clk_select_active_input(data); if (err < 0) goto cleanup;
if (initialization_required) { /* PLL configuration is required */
err = si5341_initialize_pll(data); if (err < 0) goto cleanup;
}
init.num_parents = data->num_synth;
init.parent_names = synth_clock_names;
init.ops = &si5341_output_clk_ops; for (i = 0; i < data->num_outputs; ++i) {
init.name = kasprintf(GFP_KERNEL, "%s.%d",
client->dev.of_node->name, i); if (!init.name) {
err = -ENOMEM; goto free_clk_names;
}
init.flags = config[i].synth_master ? CLK_SET_RATE_PARENT : 0;
data->clk[i].index = i;
data->clk[i].data = data;
data->clk[i].hw.init = &init; if (config[i].out_format_drv_bits & 0x07) {
regmap_write(data->regmap,
SI5341_OUT_FORMAT(&data->clk[i]),
config[i].out_format_drv_bits);
regmap_write(data->regmap,
SI5341_OUT_CM(&data->clk[i]),
config[i].out_cm_ampl_bits);
regmap_update_bits(data->regmap,
SI5341_OUT_MUX_SEL(&data->clk[i]),
SI5341_OUT_MUX_VDD_SEL_MASK,
config[i].vdd_sel_bits);
}
err = devm_clk_hw_register(&client->dev, &data->clk[i].hw);
kfree(init.name); /* clock framework made a copy of the name */ if (err) {
dev_err(&client->dev, "output %u registration failed\n", i); goto free_clk_names;
} if (config[i].always_on)
clk_prepare(data->clk[i].hw.clk);
}
err = devm_of_clk_add_hw_provider(&client->dev, of_clk_si5341_get,
data); if (err) {
dev_err(&client->dev, "unable to add clk provider\n"); goto free_clk_names;
}
if (initialization_required) { /* Synchronize */
regcache_cache_only(data->regmap, false);
err = regcache_sync(data->regmap); if (err < 0) goto free_clk_names;
err = si5341_finalize_defaults(data); if (err < 0) goto free_clk_names;
}
/* wait for device to report input clock present and PLL lock */
err = regmap_read_poll_timeout(data->regmap, SI5341_STATUS, status,
!(status & (SI5341_STATUS_LOSREF | SI5341_STATUS_LOL)),
10000, 250000); if (err) {
dev_err(&client->dev, "Error waiting for input clock or PLL lock\n"); goto free_clk_names;
}
/* clear sticky alarm bits from initialization */
err = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0); if (err) {
dev_err(&client->dev, "unable to clear sticky status\n"); goto free_clk_names;
}
err = sysfs_create_files(&client->dev.kobj, si5341_attributes); if (err)
dev_err(&client->dev, "unable to create sysfs files\n");
free_clk_names: /* Free the names, clk framework makes copies */ for (i = 0; i < data->num_synth; ++i)
devm_kfree(&client->dev, (void *)synth_clock_names[i]);
cleanup: if (err) { for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) { if (data->clk[i].vddo_reg)
regulator_disable(data->clk[i].vddo_reg);
}
} return err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.