Xilinx: ARM: I2C: SI570: Driver updated for more error checking
[linux-2.6-xlnx.git] / drivers / misc / si570.c
blob8bafd62ccfa7058fd96aa2f99c912d015d024014
1 /*
2 * Driver for Silicon Labs Si570/Si571 Programmable XO/VCXO
4 * Copyright (C) 2010, 2011 Ericsson AB.
5 * Copyright (C) 2011 Guenter Roeck.
7 * Author: Guenter Roeck <guenter.roeck@ericsson.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
20 #include <linux/module.h>
21 #include <linux/jiffies.h>
22 #include <linux/i2c.h>
23 #include <linux/err.h>
24 #include <linux/mutex.h>
25 #include <linux/delay.h>
26 #include <linux/log2.h>
27 #include <linux/slab.h>
28 #include <linux/of_i2c.h>
29 #include <linux/i2c/si570.h>
31 /* Si570 registers */
32 #define SI570_REG_HS_N1 7
33 #define SI570_REG_N1_RFREQ0 8
34 #define SI570_REG_RFREQ1 9
35 #define SI570_REG_RFREQ2 10
36 #define SI570_REG_RFREQ3 11
37 #define SI570_REG_RFREQ4 12
38 #define SI570_REG_CONTROL 135
39 #define SI570_REG_FREEZE_DCO 137
41 #define HS_DIV_SHIFT 5
42 #define HS_DIV_MASK 0xe0
43 #define HS_DIV_OFFSET 4
44 #define N1_6_2_MASK 0x1f
45 #define N1_1_0_MASK 0xc0
46 #define RFREQ_37_32_MASK 0x3f
48 #define SI570_FOUT_FACTORY_DFLT 156250000LL
49 #define SI598_FOUT_FACTORY_DFLT 10000000LL
51 #define SI570_MIN_FREQ 10000000L
52 #define SI570_MAX_FREQ 1417500000L
53 #define SI598_MAX_FREQ 525000000L
55 #define FDCO_MIN 4850000000LL
56 #define FDCO_MAX 5670000000LL
57 #define FDCO_CENTER ((FDCO_MIN + FDCO_MAX) / 2)
59 #define SI570_CNTRL_RECALL (1 << 0)
60 #define SI570_CNTRL_FREEZE_ADC (1 << 4)
61 #define SI570_CNTRL_FREEZE_M (1 << 5)
62 #define SI570_CNTRL_NEWFREQ (1 << 6)
63 #define SI570_CNTRL_RESET (1 << 7)
65 #define SI570_FREEZE_DCO (1 << 4)
66 #define SI570_UNFREEZE_DCO 0xEF
68 struct si570_data {
69 struct attribute_group attrs;
70 struct mutex lock;
71 u64 max_freq;
72 u64 fout; /* Factory default frequency */
73 u64 fxtal; /* Factory xtal frequency */
74 unsigned int n1;
75 unsigned int hs_div;
76 u64 rfreq;
77 u64 frequency;
81 static struct i2c_client *si570_client;
84 static int si570_get_defaults(struct i2c_client *client)
86 struct si570_data *data = i2c_get_clientdata(client);
87 int reg1, reg2, reg3, reg4, reg5, reg6;
88 u64 fdco;
90 i2c_smbus_write_byte_data(client, SI570_REG_CONTROL,
91 SI570_CNTRL_RECALL);
93 reg1 = i2c_smbus_read_byte_data(client, SI570_REG_HS_N1);
94 if (reg1 < 0)
95 return reg1;
96 reg2 = i2c_smbus_read_byte_data(client, SI570_REG_N1_RFREQ0);
97 if (reg2 < 0)
98 return reg2;
99 reg3 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ1);
100 if (reg3 < 0)
101 return reg3;
102 reg4 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ2);
103 if (reg4 < 0)
104 return reg4;
105 reg5 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ3);
106 if (reg5 < 0)
107 return reg5;
108 reg6 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ4);
109 if (reg6 < 0)
110 return reg6;
112 data->hs_div = ((reg1 & HS_DIV_MASK) >> HS_DIV_SHIFT) + HS_DIV_OFFSET;
113 data->n1 = ((reg1 & N1_6_2_MASK) << 2) + ((reg2 & N1_1_0_MASK) >> 6)
114 + 1;
115 /* Handle invalid cases */
116 if (data->n1 > 1)
117 data->n1 &= ~1;
119 data->rfreq = reg2 & RFREQ_37_32_MASK;
120 data->rfreq = (data->rfreq << 8) + reg3;
121 data->rfreq = (data->rfreq << 8) + reg4;
122 data->rfreq = (data->rfreq << 8) + reg5;
123 data->rfreq = (data->rfreq << 8) + reg6;
126 * Accept optional precision loss to avoid arithmetic overflows.
127 * Acceptable per Silicon Labs Application Note AN334.
129 fdco = data->fout * data->n1 * data->hs_div;
130 if (fdco >= (1LL << 36))
131 data->fxtal = div64_u64((fdco << 24), (data->rfreq >> 4));
132 else
133 data->fxtal = div64_u64((fdco << 28), data->rfreq);
135 data->frequency = data->fout;
137 return 0;
141 * Update rfreq registers
142 * This function must be called with update mutex lock held.
144 static void si570_update_rfreq(struct i2c_client *client,
145 struct si570_data *data)
147 int status;
148 status = i2c_smbus_write_byte_data(client, SI570_REG_N1_RFREQ0,
149 ((data->n1 - 1) << 6)
150 | ((data->rfreq >> 32) & RFREQ_37_32_MASK));
151 if (status < 0)
152 dev_err(&client->dev,
153 "unable to write 0x%llX to REG_N1_RFREQ0: %d\n",
154 (((data->n1 - 1) << 6) | ((data->rfreq >> 32) &
155 RFREQ_37_32_MASK)) & 0xff, status);
156 status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ1,
157 (data->rfreq >> 24) & 0xff);
158 if (status < 0)
159 dev_err(&client->dev,
160 "unable to write 0x%llX to REG_RFREQ1: %d\n",
161 (data->rfreq >> 24) & 0xff, status);
162 status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ2,
163 (data->rfreq >> 16) & 0xff);
164 if (status < 0)
165 dev_err(&client->dev,
166 "unable to write 0x%llX to REG_RFREQ2: %d\n",
167 (data->rfreq >> 16) & 0xff, status);
168 status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ3,
169 (data->rfreq >> 8) & 0xff);
170 if (status < 0)
171 dev_err(&client->dev,
172 "unable to write 0x%llX to REG_RFREQ3: %d\n",
173 (data->rfreq >> 8) & 0xff, status);
174 status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ4,
175 data->rfreq & 0xff);
176 if (status < 0)
177 dev_err(&client->dev,
178 "unable to write 0x%llX to REG_RFREQ4: %d\n",
179 data->rfreq & 0xff, status);
183 * Update si570 frequency for small frequency changes (< 3,500 ppm)
184 * This function must be called with update mutex lock held.
186 static int si570_set_frequency_small(struct i2c_client *client,
187 struct si570_data *data,
188 unsigned long frequency)
190 data->frequency = frequency;
191 /* This is a re-implementation of DIV_ROUND_CLOSEST
192 * using the div64_u64 function lieu of letting the compiler
193 * insert EABI calls
195 data->rfreq = div64_u64((data->rfreq * frequency) +
196 div64_u64(data->frequency, 2), data->frequency);
197 i2c_smbus_write_byte_data(client, SI570_REG_CONTROL,
198 SI570_CNTRL_FREEZE_M);
199 si570_update_rfreq(client, data);
200 i2c_smbus_write_byte_data(client, SI570_REG_CONTROL, 0);
202 return 0;
205 const uint8_t si570_hs_div_values[] = { 11, 9, 7, 6, 5, 4 };
208 * Set si570 frequency.
209 * This function must be called with update mutex lock held.
211 static int si570_set_frequency(struct i2c_client *client,
212 struct si570_data *data,
213 unsigned long frequency)
215 int i, n1, hs_div;
216 u64 fdco, best_fdco = ULLONG_MAX;
218 for (i = 0; i < ARRAY_SIZE(si570_hs_div_values); i++) {
219 hs_div = si570_hs_div_values[i];
220 /* Calculate lowest possible value for n1 */
221 n1 = div64_u64(div64_u64(FDCO_MIN, (u64)hs_div),
222 (u64)frequency);
223 if (!n1 || (n1 & 1))
224 n1++;
225 while (n1 <= 128) {
226 fdco = (u64)frequency * (u64)hs_div * (u64)n1;
227 if (fdco > FDCO_MAX)
228 break;
229 if (fdco >= FDCO_MIN && fdco < best_fdco) {
230 data->n1 = n1;
231 data->hs_div = hs_div;
232 data->frequency = frequency;
233 data->rfreq = div64_u64((fdco << 28),
234 data->fxtal);
235 best_fdco = fdco;
237 n1 += (n1 == 1 ? 1 : 2);
240 if (best_fdco == ULLONG_MAX) {
241 dev_err(&client->dev, "error - best FDCO is out of range\n");
242 return -EINVAL;
245 /* The DCO reg should be accessed with a read-modify-write operation
246 * per AN334
248 i2c_smbus_write_byte_data(client, SI570_REG_FREEZE_DCO,
249 SI570_FREEZE_DCO);
250 i2c_smbus_write_byte_data(client, SI570_REG_HS_N1,
251 ((data->hs_div - HS_DIV_OFFSET) <<
252 HS_DIV_SHIFT)
253 | (((data->n1 - 1) >> 2) & N1_6_2_MASK));
254 si570_update_rfreq(client, data);
255 i2c_smbus_write_byte_data(client, SI570_REG_FREEZE_DCO,
257 i2c_smbus_write_byte_data(client, SI570_REG_CONTROL,
258 SI570_CNTRL_NEWFREQ);
259 return 0;
263 * Reset chip.
264 * This function must be called with update mutex lock held.
266 static int si570_reset(struct i2c_client *client, struct si570_data *data)
268 i2c_smbus_write_byte_data(client, SI570_REG_CONTROL,
269 SI570_CNTRL_RESET);
270 usleep_range(1000, 5000);
271 return si570_set_frequency(client, data, data->frequency);
274 static ssize_t show_frequency_attr(struct device *dev,
275 struct device_attribute *devattr,
276 char *buf)
278 struct i2c_client *client = to_i2c_client(dev);
279 struct si570_data *data = i2c_get_clientdata(client);
281 return sprintf(buf, "%llu\n", data->frequency);
284 int get_frequency_si570(struct device *dev, unsigned long *freq)
286 int err;
287 char buf[10+1];
289 if ((!dev) || (to_i2c_client(dev) != si570_client))
290 return -EINVAL;
292 show_frequency_attr(dev, NULL, buf);
294 err = strict_strtoul(buf, 10, freq);
295 if (err)
296 return err;
298 return 0;
300 EXPORT_SYMBOL(get_frequency_si570);
302 static ssize_t set_frequency_attr(struct device *dev,
303 struct device_attribute *attr,
304 const char *buf, size_t count)
306 struct i2c_client *client = to_i2c_client(dev);
307 struct si570_data *data = i2c_get_clientdata(client);
308 unsigned long val;
309 int err;
311 err = strict_strtoul(buf, 10, &val);
312 if (err)
313 return err;
315 if (val < SI570_MIN_FREQ || val > data->max_freq) {
316 dev_err(&client->dev,
317 "requested frequency %lu Hz is out of range\n", val);
318 return -EINVAL;
321 mutex_lock(&data->lock);
323 if (div64_u64(abs(val - data->frequency) * 10000LL,
324 data->frequency) < 35)
325 err = si570_set_frequency_small(client, data, val);
326 else
327 err = si570_set_frequency(client, data, val);
328 mutex_unlock(&data->lock);
329 if (err) {
330 dev_warn(&client->dev,
331 "unable to set output frequency %lu Hz: %d\n",
332 val, err);
333 return err;
336 dev_info(&client->dev,
337 "set new output frequency %lu Hz\n", val);
339 return count;
342 int set_frequency_si570(struct device *dev, unsigned long freq)
344 char buf[10+1];
346 if ((!dev) || (to_i2c_client(dev) != si570_client))
347 return -EINVAL;
349 sprintf(buf, "%lu", freq);
351 return set_frequency_attr(dev, NULL, buf, 0);
353 EXPORT_SYMBOL(set_frequency_si570);
355 static ssize_t show_reset_attr(struct device *dev,
356 struct device_attribute *devattr,
357 char *buf)
359 return sprintf(buf, "%d\n", 0);
362 static ssize_t set_reset_attr(struct device *dev,
363 struct device_attribute *attr,
364 const char *buf, size_t count)
366 struct i2c_client *client = to_i2c_client(dev);
367 struct si570_data *data = i2c_get_clientdata(client);
368 unsigned long val;
369 int err;
371 err = strict_strtoul(buf, 10, &val);
372 if (err)
373 return err;
374 if (val == 0)
375 goto done;
377 mutex_lock(&data->lock);
378 err = si570_reset(client, data);
379 mutex_unlock(&data->lock);
380 if (err)
381 return err;
382 done:
383 return count;
386 int reset_si570(struct device *dev, int id)
388 char buf[4];
390 if ((!dev) || (to_i2c_client(dev) != si570_client))
391 return -EINVAL;
393 sprintf(buf, "%lu", (unsigned long)id);
394 return set_reset_attr(dev, NULL, buf, 0);
396 EXPORT_SYMBOL(reset_si570);
398 struct i2c_client *get_i2c_client_si570(void)
400 return si570_client;
402 EXPORT_SYMBOL(get_i2c_client_si570);
404 static DEVICE_ATTR(frequency, S_IWUSR | S_IRUGO, show_frequency_attr, set_frequency_attr);
405 static DEVICE_ATTR(reset, S_IWUSR | S_IRUGO, show_reset_attr, set_reset_attr);
407 static struct attribute *si570_attr[] = {
408 &dev_attr_frequency.attr,
409 &dev_attr_reset.attr,
410 NULL
413 static const struct i2c_device_id si570_id[] = {
414 { "si570", 0 },
415 { "si571", 0 },
416 { "si598", 1 },
417 { "si599", 1 },
420 MODULE_DEVICE_TABLE(i2c, si570_id);
422 static int si570_probe(struct i2c_client *client,
423 const struct i2c_device_id *id)
425 struct si570_platform_data *pdata = client->dev.platform_data;
426 struct si570_data *data;
427 int err;
428 unsigned long initial_fout;
430 data = kzalloc(sizeof(struct si570_data), GFP_KERNEL);
431 if (!data) {
432 err = -ENOMEM;
433 goto exit;
436 if (id->driver_data) {
437 data->fout = SI598_FOUT_FACTORY_DFLT;
438 data->max_freq = SI598_MAX_FREQ;
439 } else {
440 data->fout = SI570_FOUT_FACTORY_DFLT;
441 data->max_freq = SI570_MAX_FREQ;
444 if (pdata && pdata->factory_fout)
445 data->fout = pdata->factory_fout;
447 if (client->dev.of_node &&
448 (of_property_read_u64(client->dev.of_node, "factory-fout",
449 &data->fout) < 0)) {
450 dev_warn(&client->dev,
451 "DTS does not contain factory-fout, using default\n");
454 i2c_set_clientdata(client, data);
455 err = si570_get_defaults(client);
456 if (err < 0)
457 goto exit_free;
459 mutex_init(&data->lock);
461 /* Register sysfs hooks */
462 data->attrs.attrs = si570_attr;
463 err = sysfs_create_group(&client->dev.kobj, &data->attrs);
464 if (err)
465 goto exit_free;
467 /* Display a message indicating that we've successfully registered */
468 dev_info(&client->dev,
469 "registered %s with default frequency %llu Hz\n",
470 id->name, data->fout);
472 /* Read the requested initial fout from either platform data or the
473 * device tree
475 initial_fout = 0;
476 if (pdata && pdata->initial_fout) {
477 initial_fout = pdata->initial_fout;
479 if (client->dev.of_node) {
480 of_property_read_u32(client->dev.of_node, "initial-fout",
481 (u32 *)&initial_fout);
482 if (pdata && pdata->initial_fout &&
483 (pdata->initial_fout != initial_fout)) {
484 dev_warn(&client->dev,
485 "OF initial fout %lu overrides platform data fout %lu\n",
486 initial_fout,
487 pdata->initial_fout);
491 if (initial_fout != 0) {
492 if (initial_fout < SI570_MIN_FREQ ||
493 initial_fout > data->max_freq) {
494 dev_err(&client->dev,
495 "requested initial frequency %lu is out of range, using default\n",
496 initial_fout);
497 return 0;
500 mutex_lock(&data->lock);
502 if (div64_u64(abs(initial_fout - data->frequency) *
503 10000LL, data->frequency) < 35)
504 err = si570_set_frequency_small(client, data,
505 initial_fout);
506 else
507 err = si570_set_frequency(client, data,
508 initial_fout);
509 mutex_unlock(&data->lock);
510 if (err) {
511 dev_warn(&client->dev,
512 "unable to set initial output frequency %lu: %d\n",
513 initial_fout, err);
514 return err;
517 dev_info(&client->dev,
518 "set initial output frequency %lu Hz\n",
519 initial_fout);
522 si570_client = client;
524 return 0;
526 exit_free:
527 kfree(data);
528 exit:
529 return err;
532 static int si570_remove(struct i2c_client *client)
534 struct si570_data *data = i2c_get_clientdata(client);
536 sysfs_remove_group(&client->dev.kobj, &data->attrs);
537 kfree(data);
538 return 0;
541 #ifdef CONFIG_OF
542 static const struct of_device_id i2c_si570_of_match[] = {
543 { .compatible = "si570" },
544 { },
546 MODULE_DEVICE_TABLE(of, i2c_si570_of_match);
547 #endif
549 static struct i2c_driver si570_driver = {
550 .driver = {
551 .name = "si570",
552 .of_match_table = of_match_ptr(i2c_si570_of_match),
554 .probe = si570_probe,
555 .remove = si570_remove,
556 .id_table = si570_id,
559 static int __init si570_init(void)
561 return i2c_add_driver(&si570_driver);
564 static void __exit si570_exit(void)
566 i2c_del_driver(&si570_driver);
569 MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
570 MODULE_DESCRIPTION("Si570 driver");
571 MODULE_LICENSE("GPL");
573 module_init(si570_init);
574 module_exit(si570_exit);