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