1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Driver for Silicon Labs Si514 Programmable Oscillator 4 * 5 * Copyright (C) 2015 Topic Embedded Products 6 * 7 * Author: Mike Looijmans <mike.looijmans@topic.nl> 8 */ 9 10 #include <linux/clk-provider.h> 11 #include <linux/delay.h> 12 #include <linux/module.h> 13 #include <linux/i2c.h> 14 #include <linux/regmap.h> 15 #include <linux/slab.h> 16 17 /* I2C registers */ 18 #define SI514_REG_LP 0 19 #define SI514_REG_M_FRAC1 5 20 #define SI514_REG_M_FRAC2 6 21 #define SI514_REG_M_FRAC3 7 22 #define SI514_REG_M_INT_FRAC 8 23 #define SI514_REG_M_INT 9 24 #define SI514_REG_HS_DIV 10 25 #define SI514_REG_LS_HS_DIV 11 26 #define SI514_REG_OE_STATE 14 27 #define SI514_REG_RESET 128 28 #define SI514_REG_CONTROL 132 29 30 /* Register values */ 31 #define SI514_RESET_RST BIT(7) 32 33 #define SI514_CONTROL_FCAL BIT(0) 34 #define SI514_CONTROL_OE BIT(2) 35 36 #define SI514_MIN_FREQ 100000U 37 #define SI514_MAX_FREQ 250000000U 38 39 #define FXO 31980000U 40 41 #define FVCO_MIN 2080000000U 42 #define FVCO_MAX 2500000000U 43 44 #define HS_DIV_MAX 1022 45 46 struct clk_si514 { 47 struct clk_hw hw; 48 struct regmap *regmap; 49 struct i2c_client *i2c_client; 50 }; 51 #define to_clk_si514(_hw) container_of(_hw, struct clk_si514, hw) 52 53 /* Multiplier/divider settings */ 54 struct clk_si514_muldiv { 55 u32 m_frac; /* 29-bit Fractional part of multiplier M */ 56 u8 m_int; /* Integer part of multiplier M, 65..78 */ 57 u8 ls_div_bits; /* 2nd divider, as 2^x */ 58 u16 hs_div; /* 1st divider, must be even and 10<=x<=1022 */ 59 }; 60 61 /* Enables or disables the output driver */ 62 static int si514_enable_output(struct clk_si514 *data, bool enable) 63 { 64 return regmap_update_bits(data->regmap, SI514_REG_CONTROL, 65 SI514_CONTROL_OE, enable ? SI514_CONTROL_OE : 0); 66 } 67 68 static int si514_prepare(struct clk_hw *hw) 69 { 70 struct clk_si514 *data = to_clk_si514(hw); 71 72 return si514_enable_output(data, true); 73 } 74 75 static void si514_unprepare(struct clk_hw *hw) 76 { 77 struct clk_si514 *data = to_clk_si514(hw); 78 79 si514_enable_output(data, false); 80 } 81 82 static int si514_is_prepared(struct clk_hw *hw) 83 { 84 struct clk_si514 *data = to_clk_si514(hw); 85 unsigned int val; 86 int err; 87 88 err = regmap_read(data->regmap, SI514_REG_CONTROL, &val); 89 if (err < 0) 90 return err; 91 92 return !!(val & SI514_CONTROL_OE); 93 } 94 95 /* Retrieve clock multiplier and dividers from hardware */ 96 static int si514_get_muldiv(struct clk_si514 *data, 97 struct clk_si514_muldiv *settings) 98 { 99 int err; 100 u8 reg[7]; 101 102 err = regmap_bulk_read(data->regmap, SI514_REG_M_FRAC1, 103 reg, ARRAY_SIZE(reg)); 104 if (err) 105 return err; 106 107 settings->m_frac = reg[0] | reg[1] << 8 | reg[2] << 16 | 108 (reg[3] & 0x1F) << 24; 109 settings->m_int = (reg[4] & 0x3f) << 3 | reg[3] >> 5; 110 settings->ls_div_bits = (reg[6] >> 4) & 0x07; 111 settings->hs_div = (reg[6] & 0x03) << 8 | reg[5]; 112 return 0; 113 } 114 115 static int si514_set_muldiv(struct clk_si514 *data, 116 struct clk_si514_muldiv *settings) 117 { 118 u8 lp; 119 u8 reg[7]; 120 int err; 121 122 /* Calculate LP1/LP2 according to table 13 in the datasheet */ 123 /* 65.259980246 */ 124 if (settings->m_int < 65 || 125 (settings->m_int == 65 && settings->m_frac <= 139575831)) 126 lp = 0x22; 127 /* 67.859763463 */ 128 else if (settings->m_int < 67 || 129 (settings->m_int == 67 && settings->m_frac <= 461581994)) 130 lp = 0x23; 131 /* 72.937624981 */ 132 else if (settings->m_int < 72 || 133 (settings->m_int == 72 && settings->m_frac <= 503383578)) 134 lp = 0x33; 135 /* 75.843265046 */ 136 else if (settings->m_int < 75 || 137 (settings->m_int == 75 && settings->m_frac <= 452724474)) 138 lp = 0x34; 139 else 140 lp = 0x44; 141 142 err = regmap_write(data->regmap, SI514_REG_LP, lp); 143 if (err < 0) 144 return err; 145 146 reg[0] = settings->m_frac; 147 reg[1] = settings->m_frac >> 8; 148 reg[2] = settings->m_frac >> 16; 149 reg[3] = settings->m_frac >> 24 | settings->m_int << 5; 150 reg[4] = settings->m_int >> 3; 151 reg[5] = settings->hs_div; 152 reg[6] = (settings->hs_div >> 8) | (settings->ls_div_bits << 4); 153 154 err = regmap_bulk_write(data->regmap, SI514_REG_HS_DIV, reg + 5, 2); 155 if (err < 0) 156 return err; 157 /* 158 * Writing to SI514_REG_M_INT_FRAC triggers the clock change, so that 159 * must be written last 160 */ 161 return regmap_bulk_write(data->regmap, SI514_REG_M_FRAC1, reg, 5); 162 } 163 164 /* Calculate divider settings for a given frequency */ 165 static int si514_calc_muldiv(struct clk_si514_muldiv *settings, 166 unsigned long frequency) 167 { 168 u64 m; 169 u32 ls_freq; 170 u32 tmp; 171 u8 res; 172 173 if ((frequency < SI514_MIN_FREQ) || (frequency > SI514_MAX_FREQ)) 174 return -EINVAL; 175 176 /* Determine the minimum value of LS_DIV and resulting target freq. */ 177 ls_freq = frequency; 178 if (frequency >= (FVCO_MIN / HS_DIV_MAX)) 179 settings->ls_div_bits = 0; 180 else { 181 res = 1; 182 tmp = 2 * HS_DIV_MAX; 183 while (tmp <= (HS_DIV_MAX * 32)) { 184 if ((frequency * tmp) >= FVCO_MIN) 185 break; 186 ++res; 187 tmp <<= 1; 188 } 189 settings->ls_div_bits = res; 190 ls_freq = frequency << res; 191 } 192 193 /* Determine minimum HS_DIV, round up to even number */ 194 settings->hs_div = DIV_ROUND_UP(FVCO_MIN >> 1, ls_freq) << 1; 195 196 /* M = LS_DIV x HS_DIV x frequency / F_XO (in fixed-point) */ 197 m = ((u64)(ls_freq * settings->hs_div) << 29) + (FXO / 2); 198 do_div(m, FXO); 199 settings->m_frac = (u32)m & (BIT(29) - 1); 200 settings->m_int = (u32)(m >> 29); 201 202 return 0; 203 } 204 205 /* Calculate resulting frequency given the register settings */ 206 static unsigned long si514_calc_rate(struct clk_si514_muldiv *settings) 207 { 208 u64 m = settings->m_frac | ((u64)settings->m_int << 29); 209 u32 d = settings->hs_div * BIT(settings->ls_div_bits); 210 211 return ((u32)(((m * FXO) + (FXO / 2)) >> 29)) / d; 212 } 213 214 static unsigned long si514_recalc_rate(struct clk_hw *hw, 215 unsigned long parent_rate) 216 { 217 struct clk_si514 *data = to_clk_si514(hw); 218 struct clk_si514_muldiv settings; 219 int err; 220 221 err = si514_get_muldiv(data, &settings); 222 if (err) { 223 dev_err(&data->i2c_client->dev, "unable to retrieve settings\n"); 224 return 0; 225 } 226 227 return si514_calc_rate(&settings); 228 } 229 230 static long si514_round_rate(struct clk_hw *hw, unsigned long rate, 231 unsigned long *parent_rate) 232 { 233 struct clk_si514_muldiv settings; 234 int err; 235 236 if (!rate) 237 return 0; 238 239 err = si514_calc_muldiv(&settings, rate); 240 if (err) 241 return err; 242 243 return si514_calc_rate(&settings); 244 } 245 246 /* 247 * Update output frequency for big frequency changes (> 1000 ppm). 248 * The chip supports <1000ppm changes "on the fly", we haven't implemented 249 * that here. 250 */ 251 static int si514_set_rate(struct clk_hw *hw, unsigned long rate, 252 unsigned long parent_rate) 253 { 254 struct clk_si514 *data = to_clk_si514(hw); 255 struct clk_si514_muldiv settings; 256 unsigned int old_oe_state; 257 int err; 258 259 err = si514_calc_muldiv(&settings, rate); 260 if (err) 261 return err; 262 263 err = regmap_read(data->regmap, SI514_REG_CONTROL, &old_oe_state); 264 if (err) 265 return err; 266 267 si514_enable_output(data, false); 268 269 err = si514_set_muldiv(data, &settings); 270 if (err < 0) 271 return err; /* Undefined state now, best to leave disabled */ 272 273 /* Trigger calibration */ 274 err = regmap_write(data->regmap, SI514_REG_CONTROL, SI514_CONTROL_FCAL); 275 if (err < 0) 276 return err; 277 278 /* Applying a new frequency can take up to 10ms */ 279 usleep_range(10000, 12000); 280 281 if (old_oe_state & SI514_CONTROL_OE) 282 si514_enable_output(data, true); 283 284 return err; 285 } 286 287 static const struct clk_ops si514_clk_ops = { 288 .prepare = si514_prepare, 289 .unprepare = si514_unprepare, 290 .is_prepared = si514_is_prepared, 291 .recalc_rate = si514_recalc_rate, 292 .round_rate = si514_round_rate, 293 .set_rate = si514_set_rate, 294 }; 295 296 static bool si514_regmap_is_volatile(struct device *dev, unsigned int reg) 297 { 298 switch (reg) { 299 case SI514_REG_CONTROL: 300 case SI514_REG_RESET: 301 return true; 302 default: 303 return false; 304 } 305 } 306 307 static bool si514_regmap_is_writeable(struct device *dev, unsigned int reg) 308 { 309 switch (reg) { 310 case SI514_REG_LP: 311 case SI514_REG_M_FRAC1 ... SI514_REG_LS_HS_DIV: 312 case SI514_REG_OE_STATE: 313 case SI514_REG_RESET: 314 case SI514_REG_CONTROL: 315 return true; 316 default: 317 return false; 318 } 319 } 320 321 static const struct regmap_config si514_regmap_config = { 322 .reg_bits = 8, 323 .val_bits = 8, 324 .cache_type = REGCACHE_MAPLE, 325 .max_register = SI514_REG_CONTROL, 326 .writeable_reg = si514_regmap_is_writeable, 327 .volatile_reg = si514_regmap_is_volatile, 328 }; 329 330 static int si514_probe(struct i2c_client *client) 331 { 332 struct clk_si514 *data; 333 struct clk_init_data init; 334 int err; 335 336 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 337 if (!data) 338 return -ENOMEM; 339 340 init.ops = &si514_clk_ops; 341 init.flags = 0; 342 init.num_parents = 0; 343 data->hw.init = &init; 344 data->i2c_client = client; 345 346 if (of_property_read_string(client->dev.of_node, "clock-output-names", 347 &init.name)) 348 init.name = client->dev.of_node->name; 349 350 data->regmap = devm_regmap_init_i2c(client, &si514_regmap_config); 351 if (IS_ERR(data->regmap)) { 352 dev_err(&client->dev, "failed to allocate register map\n"); 353 return PTR_ERR(data->regmap); 354 } 355 356 i2c_set_clientdata(client, data); 357 358 err = devm_clk_hw_register(&client->dev, &data->hw); 359 if (err) { 360 dev_err(&client->dev, "clock registration failed\n"); 361 return err; 362 } 363 err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get, 364 &data->hw); 365 if (err) { 366 dev_err(&client->dev, "unable to add clk provider\n"); 367 return err; 368 } 369 370 return 0; 371 } 372 373 static const struct i2c_device_id si514_id[] = { 374 { "si514" }, 375 { } 376 }; 377 MODULE_DEVICE_TABLE(i2c, si514_id); 378 379 static const struct of_device_id clk_si514_of_match[] = { 380 { .compatible = "silabs,si514" }, 381 { }, 382 }; 383 MODULE_DEVICE_TABLE(of, clk_si514_of_match); 384 385 static struct i2c_driver si514_driver = { 386 .driver = { 387 .name = "si514", 388 .of_match_table = clk_si514_of_match, 389 }, 390 .probe = si514_probe, 391 .id_table = si514_id, 392 }; 393 module_i2c_driver(si514_driver); 394 395 MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>"); 396 MODULE_DESCRIPTION("Si514 driver"); 397 MODULE_LICENSE("GPL"); 398