Commit 69cf7478 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

continue working on si5338 driver

parent b20b0e79
Loading
Loading
Loading
Loading
+7 −1
Original line number Original line Diff line number Diff line
@@ -139,7 +139,7 @@
			xlnx,i2c-reset = "";
			xlnx,i2c-reset = "";


			rtc@68 {
			rtc@68 {
				compatible = "stm,m41t80";
				compatible = "stm,m41t62";
				reg = <0x68>;
				reg = <0x68>;
			};
			};


@@ -183,6 +183,12 @@
				0x1ffcf0 /* just for testing: write data 0xfc with write enable mask 0xf0 to register 0x01f */
				0x1ffcf0 /* just for testing: write data 0xfc with write enable mask 0xf0 to register 0x01f */
				0x20a0f0 /* just for testing: write data 0xa0 with write enable mask 0xf0 to register 0x020 */
				0x20a0f0 /* just for testing: write data 0xa0 with write enable mask 0xf0 to register 0x020 */
				>;
				>;
				si5338,in_pfd_ref=<0>; /* p1div_in (input divisors not used) */
				si5338,in_pfd_fb= <0>; /* unused */
				si5338,in_p1_div= <0>; /* unused */
				si5338,in_p2_div= <0>; /* unused */
				si5338,in_mux= <1>; /* in-3 */
				si5338,in_frequency= <25000000>; /* 25MHz */
			};
			};
			gpio@20{
			gpio@20{
				compatible = "ti,tca6408";
				compatible = "ti,tca6408";
+506 −20
Original line number Original line Diff line number Diff line
Index: git/drivers/misc/Kconfig
Index: git/drivers/misc/Kconfig
===================================================================
===================================================================
--- git.orig/drivers/misc/Kconfig	2013-11-29 23:33:09.275656939 -0700
--- git.orig/drivers/misc/Kconfig	2013-12-01 13:21:03.113068339 -0700
+++ git/drivers/misc/Kconfig	2013-11-29 23:33:12.155656969 -0700
+++ git/drivers/misc/Kconfig	2013-12-01 13:21:06.549068375 -0700
@@ -549,6 +549,19 @@
@@ -549,6 +549,19 @@
 	  their requirements.
 	  their requirements.
 
 
@@ -24,8 +24,8 @@ Index: git/drivers/misc/Kconfig
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
Index: git/drivers/misc/Makefile
Index: git/drivers/misc/Makefile
===================================================================
===================================================================
--- git.orig/drivers/misc/Makefile	2013-11-29 23:33:09.275656939 -0700
--- git.orig/drivers/misc/Makefile	2013-12-01 13:21:03.113068339 -0700
+++ git/drivers/misc/Makefile	2013-11-29 23:33:12.155656969 -0700
+++ git/drivers/misc/Makefile	2013-12-01 13:21:06.549068375 -0700
@@ -55,3 +55,5 @@
@@ -55,3 +55,5 @@
 obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
 obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
 obj-$(CONFIG_SRAM)		+= sram.o
 obj-$(CONFIG_SRAM)		+= sram.o
@@ -35,7 +35,7 @@ Index: git/drivers/misc/Makefile
Index: git/drivers/misc/vsc330x.c
Index: git/drivers/misc/vsc330x.c
===================================================================
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ git/drivers/misc/vsc330x.c	2013-11-29 23:33:12.155656969 -0700
+++ git/drivers/misc/vsc330x.c	2013-12-01 13:21:06.549068375 -0700
@@ -0,0 +1,872 @@
@@ -0,0 +1,872 @@
+/*!***************************************************************************
+/*!***************************************************************************
+ *! FILE NAME  : vsc330x.c
+ *! FILE NAME  : vsc330x.c
@@ -912,8 +912,8 @@ Index: git/drivers/misc/vsc330x.c
Index: git/drivers/misc/si5338.c
Index: git/drivers/misc/si5338.c
===================================================================
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ git/drivers/misc/si5338.c	2013-11-29 23:33:12.159656969 -0700
+++ git/drivers/misc/si5338.c	2013-12-01 17:28:06.337222090 -0700
@@ -0,0 +1,381 @@
@@ -0,0 +1,867 @@
+/*!***************************************************************************
+/*!***************************************************************************
+ *! FILE NAME  : si5338.c
+ *! FILE NAME  : si5338.c
+ *! DESCRIPTION: control of the Silicon Laboratories SI5338 clock generator
+ *! DESCRIPTION: control of the Silicon Laboratories SI5338 clock generator
@@ -942,6 +942,8 @@ Index: git/drivers/misc/si5338.c
+#include <linux/mutex.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of.h>
+#include <linux/math64.h>
+
+
+
+#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.0"
+#define SYSFS_PERMISSIONS         0644 /* default permissions for sysfs files */
+#define SYSFS_PERMISSIONS         0644 /* default permissions for sysfs files */
@@ -959,9 +961,22 @@ Index: git/drivers/misc/si5338.c
+
+
+#define FVCOMIN                    2200000000L
+#define FVCOMIN                    2200000000L
+#define FVCOMAX                    2840000000L
+#define FVCOMAX                    2840000000L
+#define INFREQMIN                     5000000LL
+#define INFREQMAX                   710000000LL
+
+
+#define AWE_IN_MUX                 0x1d18
+#define AWE_IN_MUX1                0x1c1c
+
+
+#define AWE_XTAL_FREQ              0x1c03
+#define AWE_PFD_REF                0x1de0
+#define AWE_PFD_FB                 0x1ee0
+#define AWE_P1DIV                  0x1d07
+#define AWE_P2DIV                  0x1e07
+
+
+
+
+static void si5338_init_of(struct i2c_client *client);
+
+
+
+static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
@@ -975,8 +990,47 @@ Index: git/drivers/misc/si5338.c
+static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+
+
+static void si5338_init_of(struct i2c_client *client);
+//static ssize_t input_xtal_freq_show (struct device *dev, struct device_attribute *attr, char *buf);
+
+//static ssize_t input_xtal_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t input_xtal_freq_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t in_frequency_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t in_frequency_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t _in_p12_div_show (struct device *dev, struct device_attribute *attr, char *buf,  int chn);
+static ssize_t _in_p12_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int chn);
+static ssize_t in_p1_div_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t in_p1_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t in_p2_div_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t in_p2_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t in_mux_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t in_mux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t in_mux_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t in_pfd_ref_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t in_pfd_ref_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t in_pfd_ref_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t in_pfd_fb_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t in_pfd_fb_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t in_pfd_fb_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t pll_ref_frequency_show (struct device *dev, struct device_attribute *attr, char *buf);
+
+
+
+/* -------------------------------------- */
+
+static s64 get_pll_in_frequency(struct i2c_client *client);
+static int set_in_mux(struct i2c_client *client, int data);
+static int get_in_mux(struct i2c_client *client);
+static int set_in_pdiv(struct i2c_client *client, int div, int chn); /*chn =0,1 */
+static int get_in_pdiv(struct i2c_client *client, int chn); /*chn =0,1 */
+static int set_in_pfd_ref_fb(struct i2c_client *client, u8 val, int chn); /*chn =0 - ref, 1 - fb*/
+static int get_in_pfd_ref_fb(struct i2c_client *client, int chn); /*chn =0,1 */
+static int set_in_frequency(struct i2c_client *client, u64 frequency);
+static u64 get_in_frequency(struct i2c_client *client);
+
+
+static s64 read_multireg64 (struct i2c_client *client, int awel, u32 * awe);
+static int write_multireg64 (struct i2c_client *client, u64 data, int awel, u32 * awe);
+static int read_field (struct i2c_client *client, u32 awe);
+static int write_field (struct i2c_client *client, u8 data, u32 awe);
+static int write_adwe(struct i2c_client *client, u32 adwe);
+static int write_adwe(struct i2c_client *client, u32 adwe);
+static int write_reg(struct i2c_client *client, u16 reg, u8 val, u8 mask);
+static int write_reg(struct i2c_client *client, u16 reg, u8 val, u8 mask);
+static int read_reg(struct i2c_client *client, u16 reg);
+static int read_reg(struct i2c_client *client, u16 reg);
@@ -1005,12 +1059,54 @@ Index: git/drivers/misc/si5338.c
+	.name  = "raw",
+	.name  = "raw",
+};
+};
+
+
+
+//static DEVICE_ATTR(xtal_freq,    SYSFS_PERMISSIONS,  input_xtal_freq_show, input_xtal_freq_store);
+static DEVICE_ATTR(xtal_freq_txt, SYSFS_PERMISSIONS & SYSFS_READONLY,  input_xtal_freq_txt_show, NULL);
+
+static DEVICE_ATTR(in_frequency,     SYSFS_PERMISSIONS,                   in_frequency_show, in_frequency_store);
+static DEVICE_ATTR(in_p1_div,        SYSFS_PERMISSIONS,                   in_p1_div_show,   in_p1_div_store);
+static DEVICE_ATTR(in_p2_div,        SYSFS_PERMISSIONS,                   in_p2_div_show,   in_p2_div_store);
+static DEVICE_ATTR(in_mux,           SYSFS_PERMISSIONS,                   in_mux_show, in_mux_store);
+static DEVICE_ATTR(in_mux_txt,       SYSFS_PERMISSIONS & SYSFS_READONLY,  in_mux_txt_show, NULL);
+static DEVICE_ATTR(in_pfd_ref,       SYSFS_PERMISSIONS,                   in_pfd_ref_show, in_pfd_ref_store);
+static DEVICE_ATTR(in_pfd_ref_txt,   SYSFS_PERMISSIONS & SYSFS_READONLY,  in_pfd_ref_txt_show, NULL);
+static DEVICE_ATTR(in_pfd_fb,        SYSFS_PERMISSIONS,                   in_pfd_fb_show, in_pfd_fb_store);
+static DEVICE_ATTR(in_pfd_fb_txt,    SYSFS_PERMISSIONS & SYSFS_READONLY,  in_pfd_fb_txt_show, NULL);
+static DEVICE_ATTR(pll_ref_frequency,SYSFS_PERMISSIONS & SYSFS_READONLY,  pll_ref_frequency_show, NULL);
+
+
+static struct attribute *input_dev_attrs[] = {
+//	&dev_attr_xtal_freq.attr,
+	&dev_attr_xtal_freq_txt.attr,
+	&dev_attr_in_frequency.attr,
+	&dev_attr_in_p1_div.attr,
+	&dev_attr_in_p2_div.attr,
+	&dev_attr_in_mux.attr,
+	&dev_attr_in_mux_txt.attr,
+	&dev_attr_in_pfd_ref.attr,
+	&dev_attr_in_pfd_ref_txt.attr,
+	&dev_attr_in_pfd_fb.attr,
+	&dev_attr_in_pfd_fb_txt.attr,
+	&dev_attr_pll_ref_frequency.attr,
+	NULL
+};
+
+static const struct attribute_group dev_attr_input_group = {
+	.attrs = input_dev_attrs,
+	.name  = "input",
+};
+
+
+
+
+static const struct i2c_device_id si5338_id[] = {
+static const struct i2c_device_id si5338_id[] = {
+	{ "si5338", 0 },
+	{ "si5338", 0 },
+	{ }
+	{ }
+};
+};
+
+
+struct si5338_data_t {
+struct si5338_data_t {
+	u64 input_frequency;
+	u64 pll_frequency;
+	int reg_addr;   /* used for raw register r/w */
+	int reg_addr;   /* used for raw register r/w */
+	int last_page;  /* value of last page accessed (bit 0 of register 255) */
+	int last_page;  /* value of last page accessed (bit 0 of register 255) */
+	struct mutex lock;
+	struct mutex lock;
@@ -1024,6 +1120,7 @@ Index: git/drivers/misc/si5338.c
+    int retval=0;
+    int retval=0;
+    if (&dev->kobj) {
+    if (&dev->kobj) {
+    	if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_raw_group)))<0) return retval;
+    	if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_raw_group)))<0) return retval;
+    	if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_input_group)))<0) return retval;
+    }
+    }
+    return retval;
+    return retval;
+}
+}
@@ -1151,6 +1248,345 @@ Index: git/drivers/misc/si5338.c
+	mutex_unlock(&clientdata->lock);
+	mutex_unlock(&clientdata->lock);
+    return count;
+    return count;
+}
+}
+/*
+static ssize_t input_xtal_freq_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client =       to_i2c_client(dev);
+	int data= read_field (client, AWE_XTAL_FREQ);
+    return sprintf(buf, "0x%02x\n",data);
+}
+static ssize_t input_xtal_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct i2c_client *client =       to_i2c_client(dev);
+	int data;
+    sscanf(buf, "%x", &data);
+    write_field (client, data, AWE_XTAL_FREQ);
+    return count;
+}
+*/
+static ssize_t input_xtal_freq_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	const char *txt[]= {"8MHz..11Mhz", "11MHz..19Mhz", "19MHz..26Mhz", "26MHz..30Mhz"};
+	struct i2c_client *client =       to_i2c_client(dev);
+	int data= read_field (client, AWE_XTAL_FREQ);
+    return sprintf(buf, "%s\n",(data>=0)?txt[data]:"error");
+}
+
+
+static ssize_t in_frequency_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client =       to_i2c_client(dev);
+	s64 freq= get_in_frequency (client);
+	if (freq<0) return -EINVAL;
+    return sprintf(buf, "%lld\n",freq);
+}
+static ssize_t in_frequency_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	int rc;
+	u64 freq;
+	struct i2c_client *client =       to_i2c_client(dev);
+    sscanf(buf, "%lld", &freq);
+    if (((rc=set_in_frequency (client, freq)))<0) return rc;
+    return count;
+}
+
+static ssize_t _in_p12_div_show (struct device *dev, struct device_attribute *attr, char *buf,  int chn)
+{
+	int div;
+	struct i2c_client *client =       to_i2c_client(dev);
+	if (((div=get_in_pdiv(client,chn)))<0) return div;
+    return sprintf(buf, "%d\n",div);
+}
+static ssize_t _in_p12_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int chn)
+{
+	struct i2c_client *client =       to_i2c_client(dev);
+	int div,rc;
+    sscanf(buf, "%d", &div);
+    if (((rc=set_in_pdiv(client, div,chn)))<0) return rc;
+    return count;
+}
+
+static ssize_t in_p1_div_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return _in_p12_div_show (dev, attr, buf, 0);
+}
+static ssize_t in_p1_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	return _in_p12_div_store(dev, attr, buf, count, 0);
+}
+
+static ssize_t in_p2_div_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return _in_p12_div_show (dev, attr, buf, 1);
+}
+static ssize_t in_p2_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	return _in_p12_div_store(dev, attr, buf, count, 1);
+}
+
+static ssize_t in_mux_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int data;
+	struct i2c_client *client =       to_i2c_client(dev);
+	if (((data=get_in_mux(client)))<0) return data;
+    return sprintf(buf, "%d\n",data);
+}
+static ssize_t in_mux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct i2c_client *client =       to_i2c_client(dev);
+	int data,rc;
+	sscanf(buf, "%d", &data);
+    if (((rc=set_in_mux(client, data)))<0) return rc;
+    return count;
+}
+static ssize_t in_mux_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	const char *mux_txt[]={"IN1/IN2(diff)","IN3(single ended)","IN1/IN2(xtal)"};
+	int data;
+	struct i2c_client *client =       to_i2c_client(dev);
+	if (((data=get_in_mux(client)))<0) return data;
+    return sprintf(buf, "%s\n",mux_txt[data]);
+}
+static ssize_t in_pfd_ref_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int data;
+	struct i2c_client *client =       to_i2c_client(dev);
+	if (((data=get_in_pfd_ref_fb(client,0)))<0) return data;
+    return sprintf(buf, "%d\n",data);
+}
+static ssize_t in_pfd_ref_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct i2c_client *client =       to_i2c_client(dev);
+	int data,rc;
+	sscanf(buf, "%d", &data);
+    if (((rc=set_in_pfd_ref_fb(client, data,0)))<0) return rc;
+    return count;
+}
+static ssize_t in_pfd_ref_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	const char *pfd_ref_txt[]={"p1div_in(refclk)","p2div_in(fbclk)","p1div_out(refclk)","p2div_out(fbclk)","xoclk","noclk"};
+	int data;
+	struct i2c_client *client =       to_i2c_client(dev);
+	if (((data=get_in_pfd_ref_fb(client,0)))<0) return data;
+    return sprintf(buf, "%s\n",pfd_ref_txt[data]);
+}
+
+static ssize_t in_pfd_fb_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int data;
+	struct i2c_client *client =       to_i2c_client(dev);
+	if (((data=get_in_pfd_ref_fb(client,1)))<0) return data;
+    return sprintf(buf, "%d\n",data);
+}
+static ssize_t in_pfd_fb_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct i2c_client *client =       to_i2c_client(dev);
+	int data,rc;
+	sscanf(buf, "%d", &data);
+    if (((rc=set_in_pfd_ref_fb(client, data,1)))<0) return rc;
+    return count;
+}
+static ssize_t in_pfd_fb_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	const char *pfd_fb_txt[]={"p2div_in(fbclk)","p1div_in(refclk)","p2div_out(fbclk)","p1div_out(refclk)","reserved","noclk"};
+	int data;
+	struct i2c_client *client =       to_i2c_client(dev);
+	if (((data=get_in_pfd_ref_fb(client,1)))<0) return data;
+    return sprintf(buf, "%s\n",pfd_fb_txt[data]);
+}
+
+static ssize_t pll_ref_frequency_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client =       to_i2c_client(dev);
+	s64 pll_in_freq= get_pll_in_frequency(client);
+	if (pll_in_freq<0) return (int) pll_in_freq;
+    return sprintf(buf, "%lld\n",pll_in_freq);
+}
+
+
+
+/* -------------------------------------- */
+
+static s64 get_pll_in_frequency(struct i2c_client *client)
+{
+	int mux;
+	int div=1;
+	s64 in_freq= get_in_frequency (client);
+	if (in_freq<0) return -EINVAL;
+	if (((mux=get_in_pfd_ref_fb(client,0)))<0) return mux;
+	if      (mux==2) div=get_in_pdiv(client,0);
+	else if (mux==3) div=get_in_pdiv(client,1);
+	if (div<0) return div;
+	return div64_u64(in_freq,div);
+}
+
+static int set_in_mux(struct i2c_client *client, int data)
+{
+	int data1,rc;
+	switch (data) {
+	case 0: data1=0; break;
+	case 1: data1=2; break;
+	case 2: data1=5; break;
+	default:
+		dev_err(&client->dev, "Invalid value for input multiplexer %d\n",data);
+		return - EINVAL;
+	}
+	if (((rc=write_field (client, data,  AWE_IN_MUX )))<0) return rc;
+	if (((rc=write_field (client, data1, AWE_IN_MUX1)))<0) return rc;
+	return 0;
+}
+
+static int get_in_mux(struct i2c_client *client)
+{
+	return read_field(client,AWE_IN_MUX );
+}
+static const u8 in_div_values[]={1,2,4,8,16,32};
+static int set_in_pdiv(struct i2c_client *client, int div, int chn) /*chn =0,1 */
+{
+	int rc;
+	u8 val;
+	for (val=0;val<(sizeof(in_div_values)/sizeof(in_div_values[0]));val++) if (in_div_values[val]==div) {
+		if (((rc=write_field (client, val,  chn?AWE_P2DIV:AWE_P1DIV )))<0) return rc;
+		return 0;
+	}
+	dev_err(&client->dev, "Invalid value for input divider: %d\n",div);
+	return - EINVAL;
+}
+
+static int get_in_pdiv(struct i2c_client *client, int chn) /*chn =0,1 */
+{
+	int rc;
+	if (((rc=read_field(client, chn?AWE_P2DIV:AWE_P1DIV )))<0) return rc;
+	if (rc>=(sizeof(in_div_values)/sizeof(in_div_values[0]))){
+		dev_err(&client->dev, "Invalid value for input divider: %d\n",rc);
+		return - EINVAL;
+	}
+	return in_div_values[rc];
+}
+
+static int set_in_pfd_ref_fb(struct i2c_client *client, u8 val, int chn) /*chn =0 - ref, 1 - fb*/
+{
+	int rc;
+	if (val>5) {
+		dev_err(&client->dev, "Invalid value for input pfd selector: %d\n", (int) val);
+		return - EINVAL;
+	}
+	if (((rc=write_field (client, val,  chn?AWE_PFD_FB:AWE_PFD_REF )))<0) return rc;
+	return 0;
+}
+
+static int get_in_pfd_ref_fb(struct i2c_client *client, int chn) /*chn =0,1 */
+{
+	return read_field(client, chn?AWE_PFD_FB:AWE_PFD_REF );
+}
+
+static int set_in_frequency(struct i2c_client *client, u64 frequency)
+{
+	int xtal_mode;
+	struct si5338_data_t *clientdata = i2c_get_clientdata(client);
+	if (frequency < INFREQMIN){
+		dev_err(&client->dev, "Input frequency too low: %llu < %llu\n",frequency, INFREQMIN);
+		return - EINVAL;
+	}
+	if (frequency > INFREQMAX){
+		dev_err(&client->dev, "Input frequency too high: %llu > %llu\n",frequency, INFREQMAX);
+		return - EINVAL;
+	}
+	clientdata->input_frequency=frequency;
+	/* set xtal mode */
+	xtal_mode=0;
+	if (frequency>11000000ll) xtal_mode=1;
+	if (frequency>19000000ll) xtal_mode=2;
+	if (frequency>26000000ll) xtal_mode=3;
+	return write_field (client, xtal_mode, AWE_XTAL_FREQ);
+}
+static u64 get_in_frequency(struct i2c_client *client)
+{
+	struct si5338_data_t *clientdata = i2c_get_clientdata(client);
+	return clientdata->input_frequency;
+}
+
+/* -------------------------------------- */
+
+static s64 read_multireg64 (struct i2c_client *client, int awel, u32 * awe)
+{
+	int i,nshift,nbits, full_shift=0;
+	u8 mask;
+	u16 reg;
+	s64 data=0, rc;
+	for (i=0;i<awel;i++){
+		reg=awe[i]>>8;
+		mask=awe[i]&0xff;
+		if (mask!=0){
+			nshift=0;
+			nbits=1;
+			while (((1<<nshift) & mask)==0) nshift++;
+			while (((1<<(nshift+nbits)) & mask)!=0) nbits++;
+			if (((rc=read_reg(client, reg)))<0) return rc;
+			rc &=  mask;
+			rc >>= nshift;
+			rc <<= full_shift;
+			data |= rc;
+			full_shift+=nbits;
+		}
+	}
+	return data;
+}
+
+
+static int write_multireg64 (struct i2c_client *client, u64 data, int awel, u32 * awe)
+{
+	int i,rc,nshift,nbits;
+	u8 mask,reg_data;
+	u16 reg;
+	for (i=0;i<awel;i++){
+		reg=awe[i]>>8;
+		mask=awe[i]&0xff;
+		if (mask!=0){
+			nshift=0;
+			nbits=1;
+			while (((1<<nshift) & mask)==0) nshift++;
+			while (((1<<(nshift+nbits)) & mask)!=0) nbits++;
+			reg_data=(data & 0xff) << nshift; /* may have some garbage in high bits, will be cut of by mask */
+			data >>= nbits;
+			if (((rc=write_reg(client, reg, reg_data, mask)))<0) return rc;
+		}
+	}
+	return 0;
+}
+
+static int read_field (struct i2c_client *client, u32 awe)
+{
+	int rc,nshift;
+	u8 mask;
+	u16 reg;
+	reg=awe>>8;
+	mask=awe&0xff;
+	if (mask!=0){
+		nshift=0;
+		while (((1<<nshift) & mask)==0) nshift++;
+		if (((rc=read_reg(client, reg)))<0) return rc;
+		return (rc & mask) >> nshift;
+	}
+	return 0;
+}
+
+
+static int write_field (struct i2c_client *client, u8 data, u32 awe)
+{
+	int rc,nshift;
+	u8 mask,reg_data;
+	u16 reg;
+	reg=awe>>8;
+	mask=awe&0xff;
+	if (mask!=0){
+		nshift=0;
+		while (((1<<nshift) & mask)==0) nshift++;
+		reg_data=(data & 0xff) << nshift;
+		if (((rc=write_reg(client, reg, reg_data, mask)))<0) return rc;
+	}
+}
+
+
+
+static int write_adwe(struct i2c_client *client, u32 adwe)
+static int write_adwe(struct i2c_client *client, u32 adwe)
+{
+{
@@ -1158,7 +1594,6 @@ Index: git/drivers/misc/si5338.c
+	u8 data= (adwe>>8) & 0xff;
+	u8 data= (adwe>>8) & 0xff;
+	u16 reg=  (adwe>>16) & (0xff | (REG5338_PAGE_MASK << 8)); /* 0x1ff */
+	u16 reg=  (adwe>>16) & (0xff | (REG5338_PAGE_MASK << 8)); /* 0x1ff */
+	return write_reg(client, reg, data, we);
+	return write_reg(client, reg, data, we);
+
+}
+}
+
+
+static int _write_single_reg(struct i2c_client *client, u8 reg, u8 val)
+static int _write_single_reg(struct i2c_client *client, u8 reg, u8 val)
@@ -1213,7 +1648,7 @@ Index: git/drivers/misc/si5338.c
+//	struct device *dev=&client->dev;
+//	struct device *dev=&client->dev;
+	const __be32 * config_data;
+	const __be32 * config_data;
+	struct device_node *node = client->dev.of_node;
+	struct device_node *node = client->dev.of_node;
+    int len,i,rc;
+    int len,i;
+    u16 page_reg;
+    u16 page_reg;
+    struct si5338_setup_data  {
+    struct si5338_setup_data  {
+    	u8		page;
+    	u8		page;
@@ -1234,15 +1669,62 @@ Index: git/drivers/misc/si5338.c
+				page_reg=setup_data.reg+(setup_data.page<<8);
+				page_reg=setup_data.reg+(setup_data.page<<8);
+			    dev_dbg(&client->dev,"page_reg=0x%03x, data=0x%02x, mask=0x%02x \n",
+			    dev_dbg(&client->dev,"page_reg=0x%03x, data=0x%02x, mask=0x%02x \n",
+			    		(int) page_reg,(int)setup_data.data,(int)setup_data.mask);
+			    		(int) page_reg,(int)setup_data.data,(int)setup_data.mask);
+			    if (((rc=write_reg(client, page_reg, setup_data.data, setup_data.mask)))<0) return rc;
+			    if (write_reg(client, page_reg, setup_data.data, setup_data.mask)<0) return;
+			}
+			}
+		} else {
+//		} else {
+			dev_info(&client->dev,"'si5338,configuration_data' not found in the Device Tree\n");
+//			dev_info(&client->dev,"'si5338,configuration_data' not found in the Device Tree\n");
+		}
+		/* input section */
+		config_data = of_get_property(client->dev.of_node, "si5338,in_pfd_ref", &len);
+		if (config_data && (len>0)) {
+			dev_info(&client->dev,"Found '%s', value = %d (0x%x)\n","si5338,in_pfd_ref",(int)(be32_to_cpup(config_data)),(int)(be32_to_cpup(config_data)));
+			set_in_pfd_ref_fb(client, be32_to_cpup(config_data), 0);
+		}
+		config_data = of_get_property(client->dev.of_node, "si5338,in_pfd_fb", &len);
+		if (config_data && (len>0)){
+			dev_info(&client->dev,"Found '%s', value = %d (0x%x)\n","si5338,in_pfd_fb",(int)(be32_to_cpup(config_data)),(int)(be32_to_cpup(config_data)));
+			set_in_pfd_ref_fb(client, be32_to_cpup(config_data), 1);
+		}
+		config_data = of_get_property(client->dev.of_node, "si5338,in_p1_div", &len);
+		if (config_data && (len>0)) {
+			dev_info(&client->dev,"Found '%s', value = %d (0x%x)\n","si5338,in_p1_div",(int)(be32_to_cpup(config_data)),(int)(be32_to_cpup(config_data)));
+			set_in_pdiv(client, be32_to_cpup(config_data), 0);
+		}
+		config_data = of_get_property(client->dev.of_node, "si5338,in_p2_div", &len);
+		if (config_data && (len>0)) {
+			dev_info(&client->dev,"Found '%s', value = %d (0x%x)\n","si5338,in_p2_div",(int)(be32_to_cpup(config_data)),(int)(be32_to_cpup(config_data)));
+			set_in_pdiv(client, be32_to_cpup(config_data), 1);
+		}
+		config_data = of_get_property(client->dev.of_node, "si5338,in_mux", &len);
+		if (config_data && (len>0)) {
+			dev_info(&client->dev,"Found '%s', value = %d (0x%x)\n","si5338,in_mux",(int)(be32_to_cpup(config_data)),(int)(be32_to_cpup(config_data)));
+			set_in_mux(client, be32_to_cpup(config_data));
+		}
+		config_data = of_get_property(client->dev.of_node, "si5338,in_frequency", &len);
+		if (config_data && (len>0)) {
+			dev_info(&client->dev,"Found '%s', value = %d (0x%x)\n","si5338,in_frequency",(int)(be32_to_cpup(config_data)),(int)(be32_to_cpup(config_data)));
+			set_in_frequency(client, be32_to_cpup(config_data)); /* 32 bits are sufficient here */
+		}
+		}
+/*
+si5338 0-0070: Chip si5338 is found, driver version 1.0
+si5338 0-0070: Found 2 items in 'si5338,configuration_data' in the Device Tree
+si5338 0-0070: Invalid value for input multiplexer 16777216
+si5338 0-0070: Input frequency too high: 1081638145 > 710000000
+ */
+	} else {
+	} else {
+		dev_info(&client->dev,"Device tree data not found for %s\n",client->name);
+		dev_info(&client->dev,"Device tree data not found for %s\n",client->name);
+	}
+	}
+}
+}
+#if 0
+si5338,in_pfd_ref=<0>; /* p1div_in (input divisors not used) */
+si5338,in_pfd_fb= <0>; /* unused */
+si5338,in_p1_div= <0>; /* unused */
+si5338,in_p2_div= <0>; /* unused */
+si5338,in_mux= <1>; /* in-3 */
+si5338,in_frequency= <25000000>; /* 25MHz */
+
+#endif
+
+
+
+static int si5338_i2c_probe(struct i2c_client *client,
+static int si5338_i2c_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+				      const struct i2c_device_id *id)
@@ -1269,6 +1751,10 @@ Index: git/drivers/misc/si5338.c
+	if (((rc=read_reg(client, REG5338_PAGE)))<0) return rc; // will set clientdata->last_page
+	if (((rc=read_reg(client, REG5338_PAGE)))<0) return rc; // will set clientdata->last_page
+	si5338_sysfs_register(&client->dev);
+	si5338_sysfs_register(&client->dev);
+	mutex_init(&clientdata->lock);
+	mutex_init(&clientdata->lock);
+
+	clientdata->input_frequency=0;
+	clientdata->pll_frequency=0;
+
+	si5338_init_of(client);
+	si5338_init_of(client);
+	return 0;
+	return 0;
+}
+}