Loading recipes-kernel/linux/linux-xlnx/vsc3304.patch +300 −34 Original line number Diff line number Diff line Index: git/drivers/misc/Kconfig =================================================================== --- git.orig/drivers/misc/Kconfig 2013-12-02 23:08:01.002329798 -0700 +++ git/drivers/misc/Kconfig 2013-12-02 23:08:03.994329829 -0700 --- git.orig/drivers/misc/Kconfig 2013-12-03 15:26:18.686938629 -0700 +++ git/drivers/misc/Kconfig 2013-12-03 15:26:21.590938659 -0700 @@ -549,6 +549,19 @@ their requirements. Loading @@ -24,8 +24,8 @@ Index: git/drivers/misc/Kconfig source "drivers/misc/eeprom/Kconfig" Index: git/drivers/misc/Makefile =================================================================== --- git.orig/drivers/misc/Makefile 2013-12-02 23:08:01.002329798 -0700 +++ git/drivers/misc/Makefile 2013-12-02 23:08:03.994329829 -0700 --- git.orig/drivers/misc/Makefile 2013-12-03 15:26:18.686938629 -0700 +++ git/drivers/misc/Makefile 2013-12-03 15:26:21.590938659 -0700 @@ -55,3 +55,5 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o Loading @@ -35,7 +35,7 @@ Index: git/drivers/misc/Makefile Index: git/drivers/misc/vsc330x.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ git/drivers/misc/vsc330x.c 2013-12-02 23:08:03.998329829 -0700 +++ git/drivers/misc/vsc330x.c 2013-12-03 15:26:21.594938659 -0700 @@ -0,0 +1,872 @@ +/*!*************************************************************************** + *! FILE NAME : vsc330x.c Loading Loading @@ -912,8 +912,8 @@ Index: git/drivers/misc/vsc330x.c Index: git/drivers/misc/si5338.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ git/drivers/misc/si5338.c 2013-12-02 23:17:35.422335756 -0700 @@ -0,0 +1,1493 @@ +++ git/drivers/misc/si5338.c 2013-12-03 22:08:01.215188627 -0700 @@ -0,0 +1,1759 @@ +/*!*************************************************************************** + *! FILE NAME : si5338.c + *! DESCRIPTION: control of the Silicon Laboratories SI5338 clock generator Loading Loading @@ -986,6 +986,8 @@ Index: git/drivers/misc/si5338.c +#define AWE_VCO_GAIN 0x3170 +#define AWE_RSEL 0x310c +#define AWE_BWSEL 0x3103 +#define AWE_VCO_GAIN_RSEL_BWSEL 0x317f + +#define AWE_PLL_EN 0x32c0 +#define AWE_MSCAL 0x323f +#define AWE_MS3_HS 0x3380 Loading Loading @@ -1071,6 +1073,13 @@ Index: git/drivers/misc/si5338.c +#define AWE_MSN_P3_23_16 0x69ff +#define AWE_MSN_P3_29_24 0x6a3f + +#define AWE_MISC_47 0x2ffc /* write 0x5 */ +#define AWE_MISC_106 0x6a80 /* write 0x1 */ +#define AWE_MISC_116 0x7480 /* write 0x1 */ +#define AWE_MISC_42 0x2a20 /* write 0x1 */ +#define AWE_MISC_06A 0x06e0 /* write 0x0 */ +#define AWE_MISC_06B 0x0602 /* write 0x0 */ +#define AWE_MISC_28 0x1cc0 /* write 0x0 */ + +static void si5338_init_of(struct i2c_client *client); + Loading Loading @@ -1142,9 +1151,25 @@ Index: git/drivers/misc/si5338.c +static ssize_t pll_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_by_out_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_by_out_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t _pll_ms_freq_show(struct device *dev, struct device_attribute *attr, char *buf, int chn); +static ssize_t _pll_ms_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,int int_div, int chn); +static ssize_t pll_ms0_freq_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t pll_ms1_freq_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t pll_ms2_freq_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t pll_ms3_freq_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t pll_ms0_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms1_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms2_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms3_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms0_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms1_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms2_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms3_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); + + +/* -------------------------------------- */ +static int set_pll_paremeters(struct i2c_client *client); +static int set_misc_registers(struct i2c_client *client); +static int ms_to_p123(u64* ms,u32 * p123); +static int p123_to_ms(u64* ms,u32 * p123); +static int get_ms_p123(struct i2c_client *client,u32 * p123, int chn); /* chn 0,1,2,3,4 (4 - msn) */ Loading @@ -1153,7 +1178,8 @@ Index: git/drivers/misc/si5338.c +static int get_pll_freq(struct i2c_client *client,u64 * pll_freq); +static int set_pll_freq_by_out(struct i2c_client *client, u64 *out_freq, int int_msn_div); + + +static int get_pll_ms_freq(struct i2c_client *client, u64 *out_freq, int chn); +static int set_pll_ms_by_out(struct i2c_client *client, u64 *out_freq, int chn, int int_div); +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); Loading Loading @@ -1273,12 +1299,30 @@ Index: git/drivers/misc/si5338.c +static DEVICE_ATTR(pll_by_out_int, SYSFS_PERMISSIONS, pll_freq_show, pll_by_out_int_store); + + +static DEVICE_ATTR(pll_ms0_freq_fract,SYSFS_PERMISSIONS, pll_ms0_freq_show, pll_ms0_freq_fract_store); +static DEVICE_ATTR(pll_ms0_freq_int, SYSFS_PERMISSIONS, pll_ms0_freq_show, pll_ms0_freq_int_store); +static DEVICE_ATTR(pll_ms1_freq_fract,SYSFS_PERMISSIONS, pll_ms1_freq_show, pll_ms1_freq_fract_store); +static DEVICE_ATTR(pll_ms1_freq_int, SYSFS_PERMISSIONS, pll_ms1_freq_show, pll_ms1_freq_int_store); +static DEVICE_ATTR(pll_ms2_freq_fract,SYSFS_PERMISSIONS, pll_ms2_freq_show, pll_ms2_freq_fract_store); +static DEVICE_ATTR(pll_ms2_freq_int, SYSFS_PERMISSIONS, pll_ms2_freq_show, pll_ms2_freq_int_store); +static DEVICE_ATTR(pll_ms3_freq_fract,SYSFS_PERMISSIONS, pll_ms3_freq_show, pll_ms3_freq_fract_store); +static DEVICE_ATTR(pll_ms3_freq_int, SYSFS_PERMISSIONS, pll_ms3_freq_show, pll_ms3_freq_int_store); + + +static struct attribute *pll_dev_attrs[] = { + &dev_attr_pll_ref_frequency.attr, + &dev_attr_pll_freq_fract.attr, + &dev_attr_pll_freq_int.attr, + &dev_attr_pll_by_out_fract.attr, + &dev_attr_pll_by_out_int.attr, + &dev_attr_pll_ms0_freq_fract.attr, + &dev_attr_pll_ms0_freq_int.attr, + &dev_attr_pll_ms1_freq_fract.attr, + &dev_attr_pll_ms1_freq_int.attr, + &dev_attr_pll_ms2_freq_fract.attr, + &dev_attr_pll_ms2_freq_int.attr, + &dev_attr_pll_ms3_freq_fract.attr, + &dev_attr_pll_ms3_freq_int.attr, + NULL +}; + Loading Loading @@ -1439,22 +1483,7 @@ Index: git/drivers/misc/si5338.c + mutex_unlock(&clientdata->lock); + 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"}; Loading Loading @@ -1734,8 +1763,13 @@ Index: git/drivers/misc/si5338.c + } + if (by_out) { + if (((rc=set_pll_freq_by_out(client, freq, int_div)))<0) return rc; + if (((rc=set_pll_paremeters(client)))<0) return rc; + if (((rc=set_misc_registers(client)))<0) return rc; + + } else { + if (((rc=set_pll_freq (client, freq, int_div)))<0) return rc; + if (((rc=set_pll_paremeters(client)))<0) return rc; + if (((rc=set_misc_registers(client)))<0) return rc; + } + return count; +} Loading @@ -1748,14 +1782,129 @@ Index: git/drivers/misc/si5338.c +static ssize_t pll_by_out_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) + {return _pll_freq_store(dev, attr, buf, count, 1, 1);} + +static ssize_t _pll_ms_freq_show(struct device *dev, struct device_attribute *attr, char *buf, int chn) +{ + int rc; + u64 ms_freq[3]; + struct i2c_client *client = to_i2c_client(dev); + + if (((rc=get_pll_ms_freq(client, ms_freq, chn)))<0) return rc; + return sprintf(buf, "%lld %lld %lld\n",ms_freq[0],ms_freq[1],ms_freq[2]); +} +static ssize_t _pll_ms_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,int int_div, int chn) +{ + struct i2c_client *client = to_i2c_client(dev); + int rc; + u64 freq[3]; + int num_items; + num_items=sscanf(buf, "%lld %lld %lld", &freq[0], &freq[1], &freq[2]); + if (num_items<3){ + freq[1]=0; + freq[2]=1; + } + if (((rc=set_pll_ms_by_out(client, freq, chn, int_div)))<0) return rc; + return count; +} +static ssize_t pll_ms0_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{return _pll_ms_freq_show(dev, attr, buf, 0);} +static ssize_t pll_ms1_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{return _pll_ms_freq_show(dev, attr, buf, 1);} +static ssize_t pll_ms2_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{return _pll_ms_freq_show(dev, attr, buf, 2);} +static ssize_t pll_ms3_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{return _pll_ms_freq_show(dev, attr, buf, 3);} +static ssize_t pll_ms0_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 0, 0);} +static ssize_t pll_ms1_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 0, 1);} +static ssize_t pll_ms2_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 0, 2);} +static ssize_t pll_ms3_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 0, 3);} +static ssize_t pll_ms0_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 1, 0);} +static ssize_t pll_ms1_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 1, 1);} +static ssize_t pll_ms2_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 1, 2);} +static ssize_t pll_ms3_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 1, 3);} + + +/* -----------PLL section--------------------------- */ +/* Setting PLL frequency in 3 ways: + * 1 - specified directly, allow fractional MSN + * 2 - specified directly, integer MSN + * 3 - specified by output frequency, integer MSN + */ +static int set_pll_paremeters(struct i2c_client *client) +{ + int rc; + s64 pll_in_freq; + u64 pll_out_freq[3]; + s64 K,Q,kphi_nom,kphi_denom,fvco_mhz, fpfd_mhz; + int rsel,bwsel,vco_gain,pll_kphi,mscal,ms_pec; + if (((pll_in_freq=get_pll_in_frequency(client)))<0) return (int) pll_in_freq; + if (((rc=get_pll_freq(client,pll_out_freq)))<0) return rc; + fpfd_mhz = div64_u64(pll_in_freq,1000000ll); + fvco_mhz = div64_u64(pll_out_freq[0],1000000ll); + if (fpfd_mhz>=15){ + K=925; + rsel=0; + bwsel=0; + } else if (fpfd_mhz>=8){ + K=325; + rsel=1; + bwsel=1; + } else { + K=185; + rsel=3; + bwsel=2; + } + if (fvco_mhz>2425){ + Q=3; + vco_gain=0; + } else { + Q=4; + vco_gain=1; + } + kphi_nom= K*2500LL*2500LL*2500LL; + kphi_denom=533LL*Q*fpfd_mhz*fvco_mhz*fvco_mhz; + pll_kphi=(int) div64_u64(kphi_nom + (kphi_denom>>1),kphi_denom); + if ((pll_kphi<1) || (pll_kphi>127)) { + dev_err(&client->dev, "Calculated PLL_KPHI does not fit 1<=%d<=127\n",pll_kphi); + if (pll_kphi<1) pll_kphi=1; + else if (pll_kphi>127) pll_kphi=127; + } + mscal = (int) div64_u64(2067000-667*fvco_mhz+50000,100000ll); + if ((mscal<0) || (mscal>63)) { + dev_err(&client->dev, "Calculated MSCAL does not fit 0<=%d<=63\n",mscal); + if (mscal<0) mscal=0; + else if (mscal>63) mscal=63; + } + ms_pec = 7; + dev_dbg(&client->dev, "Calculated values: PLL_KPHI=%d K=%lld RSEL=%d BWSEL=%d VCO_GAIN=%d MSCAL=%d MS_PEC=%d\n", + pll_kphi, K, rsel, bwsel, vco_gain, mscal, ms_pec); + /* setting actual registers */ + if (((rc=write_field(client, (u8) pll_kphi, AWE_PLL_KPHI)))<0) return rc; + if (((rc=write_field(client, (u8) (((vco_gain & 7)<<4) | ((rsel & 3)<<2) | (bwsel & 3)), + AWE_VCO_GAIN_RSEL_BWSEL)))<0) return rc; + if (((rc=write_field(client, (u8) mscal, AWE_MSCAL )))<0) return rc; + if (((rc=write_field(client, (u8) ms_pec, AWE_MS_PEC)))<0) return rc; + return 0; +} + +static int set_misc_registers(struct i2c_client *client) +{ + /* ST52238 Reference Manual R1.2 p.28 */ + int rc; + if (((rc=write_field(client, 0x5, AWE_MISC_47 )))<0) return rc; + if (((rc=write_field(client, 0x1, AWE_MISC_106 )))<0) return rc; + if (((rc=write_field(client, 0x1, AWE_MISC_116 )))<0) return rc; + if (((rc=write_field(client, 0x1, AWE_MISC_42 )))<0) return rc; + if (((rc=write_field(client, 0x0, AWE_MISC_06A )))<0) return rc; + if (((rc=write_field(client, 0x0, AWE_MISC_06B )))<0) return rc; + if (((rc=write_field(client, 0x0, AWE_MISC_28 )))<0) return rc; + return 0; +} + + +/* -----------MultiSynth section--------------------------- */ +static u32 awe_msx[5][3][5]= + {{{AWE_MS0_P1_07_00, AWE_MS0_P1_15_08, AWE_MS0_P1_17_16, 0, 0}, + {AWE_MS0_P2_05_00, AWE_MS0_P2_13_06, AWE_MS0_P2_21_14, AWE_MS0_P2_29_22, 0}, Loading Loading @@ -1824,6 +1973,10 @@ Index: git/drivers/misc/si5338.c +{ + int i; + s64 rc; + if ((chn<0) || (chn>4)){ + dev_err(&client->dev, "Invalid channel %d. Only 0,1,2,3 and 4 (for MSN) are supported\n",chn); + return - EINVAL; + } + for (i=0;i<3;i++){ + if (((rc=read_multireg64 (client, awe_msx[chn][i])))<0) return (int) rc; + p123[i]= (u32) rc; Loading @@ -1833,12 +1986,22 @@ Index: git/drivers/misc/si5338.c +static int set_ms_p123(struct i2c_client *client,u32 * p123, int chn) /* chn 0,1,2,3,4 (4 - msn) */ +{ + int i,rc; + if ((chn<0) || (chn>4)){ + dev_err(&client->dev, "Invalid channel %d. Only 0,1,2,3 and 4 (for MSN) are supported\n",chn); + return - EINVAL; + } + for (i=0;i<3;i++){ + if (((rc=write_multireg64(client, (u64) p123[i], awe_msx[chn][i])))<0) return rc; + } + return 0; +} + +/* Setting PLL frequency in 3 ways: + * 1 - specified directly, allow fractional MSN + * 2 - specified directly, integer MSN + * 3 - specified by output frequency, allow fractional MSN (use PPL frequency closest to the middle) + * 4 - specified by output frequency, integer MSN + */ +static int set_pll_freq(struct i2c_client *client, u64 *vco_freq, int int_div) +{ + s64 pll_in_freq, pll_in_freq_scaled,pll_out_freq_scaled,d; Loading Loading @@ -1892,7 +2055,7 @@ Index: git/drivers/misc/si5338.c + ms_to_p123(msn, msn_p123); + return set_ms_p123(client,msn_p123, 4); // MSN +} + +/* normalizes output */ +static int get_pll_freq(struct i2c_client *client,u64 * pll_freq) +{ + int rc; Loading Loading @@ -1924,15 +2087,20 @@ Index: git/drivers/misc/si5338.c +{ + /* use r-divider if the output frequency is too low (less than 5 MHz) */ + u64 out_int=out_freq[0],out_nom=out_freq[1],out_denom=out_freq[2], + pll_out_freq[3], scaled_max,scaled_min; + pll_out_freq[3], scaled_max,scaled_min,d; + s64 pll_freq_scaled, out_freq_scaled,err,best_err=-1,out_div,pll_in_freq,in_div,best_in_div, + pll_in_freq_scaled,synth_out_scaled; + int r_div=1; + if (out_denom<out_nom){ + dev_err(&client->dev, "Nominator (%lld) should be less than denominator (%lld)\n", + out_nom,out_denom); + if (out_denom==0){ + dev_err(&client->dev, "Denominator should not be 0 in %lld+%lld/%lld\n", + out_int,out_nom,out_denom); + return -EINVAL; + } + if (out_nom>=out_denom){ /* normalize */ + d=div64_u64(out_nom,out_denom); + out_int+=d; + out_nom-=d*out_denom; + } + if (out_int<(FVCOMAX/MSINT_MAX)){ + while ((r_div < 32) && (out_int<(FVCOMAX/MSINT_MAX))){ + out_int<<=1; Loading Loading @@ -2014,8 +2182,106 @@ Index: git/drivers/misc/si5338.c + return set_pll_freq(client, pll_out_freq, 0); /* integer result */ + } +} +static int get_pll_ms_freq(struct i2c_client *client, u64 *out_freq, int chn) +{ + int rc; + u64 pll_out_freq[3], ms[3], pll_freq_scaled, ms_scaled; + u32 p123[3]; + if (((rc=get_pll_freq(client,pll_out_freq)))<0) return rc; + /* trim PLL frequency fraction */ + while (pll_out_freq[2]>=0x1000){ + pll_out_freq[1] >>= 1; + pll_out_freq[2] >>= 1; + } + pll_freq_scaled=pll_out_freq[0]*pll_out_freq[2]+pll_out_freq[1]; + + if (((rc=get_ms_p123(client,p123, chn)))<0) return rc; /* includes invalid chn */ + p123_to_ms(ms,p123); + /* trim MS divisor fraction */ + while (ms[2]>=0x1000){ + ms[1] >>= 1; + ms[2] >>= 1; + } + ms_scaled=ms[0]*ms[2]+ms[1]; + out_freq[1]=pll_freq_scaled*ms[2]; + out_freq[2]=ms[0]*pll_out_freq[2]; + out_freq[0]=div64_u64(out_freq[1],out_freq[2]); + out_freq[1]-=out_freq[0]*out_freq[2]; + dev_dbg(&client->dev, "MS%d output frequency: %llu+%llu/%llu Hz\n",chn,out_freq[0],out_freq[1],out_freq[2]); + return 0; +} + +/* + * Adjust MultiSynth divisor (MS0..MS3) for specified output frequency + * MSN, input frequency should be already set + * out_freq as int,nom,denom + */ +static int set_pll_ms_by_out(struct i2c_client *client, u64 *out_freq, int chn, int int_div) +{ + /* use r-divider if the output frequency is too low (less than 5 MHz) */ + u64 out_int=out_freq[0],out_nom=out_freq[1],out_denom=out_freq[2], + pll_out_freq[3],d; + s64 pll_freq_scaled, out_freq_scaled; + u64 ms[3]; + u32 p123[3]; + int r_div=1,rc; + if (out_denom==0){ + dev_err(&client->dev, "Denominator should not be 0 in %lld+%lld/%lld\n", + out_int,out_nom,out_denom); + return -EINVAL; + } + if (out_nom>=out_denom){ /* normalize */ + d=div64_u64(out_nom,out_denom); + out_int+=d; + out_nom-=d*out_denom; + } + if (out_int<(FVCOMAX/MSINT_MAX)){ + while ((r_div < 32) && (out_int<(FVCOMAX/MSINT_MAX))){ + out_int<<=1; + out_nom<<=1; + r_div<<=1; + if (out_nom>out_denom) { + out_int++; + out_nom-=out_denom; + } + + } + if (out_int<(FVCOMAX/MSINT_MAX)){ + dev_err(&client->dev, "Specified output frequency is too low: %lld < %lld\n", + out_freq[0], FVCOMAX/MSINT_MAX/32); + return -EINVAL; + } + } + dev_dbg(&client->dev, "Output divider by %u, Output frequency before divider: %llu+%llu/%llu Hz\n", + r_div,out_int, out_nom,out_denom); + /* trim output frequency fraction */ + while (out_denom>=0x1000){ + out_nom >>= 1; + out_denom >>= 1; + } + out_freq_scaled=out_int*out_denom+out_nom; + if (((rc=get_pll_freq(client,pll_out_freq)))<0) return rc; + /* trim PLL frequency fraction */ + while (pll_out_freq[2]>=0x1000){ + pll_out_freq[1] >>= 1; + pll_out_freq[2] >>= 1; + } + pll_freq_scaled=pll_out_freq[0]*pll_out_freq[2]+pll_out_freq[1]; + ms[1]=pll_freq_scaled*out_denom; + ms[2]=out_freq_scaled*pll_out_freq[2]; + ms[0]=div64_u64(ms[1],ms[2]); + ms[1]-=ms[0]*ms[2]; + if (int_div){ + if (ms[1]>(ms[2]>>1)) ms[0]++; + ms[1]=0; + ms[2]=1; + } + dev_dbg(&client->dev, "MS%d divider: %llu+%llu/%llu\n",chn,ms[0],ms[1],ms[2]); + /* set up registers */ + ms_to_p123(ms,p123); + if (((rc=set_ms_p123(client,p123, chn)))<0) return rc; + return 0; +} + +/* ----------- Input section ----------------- */ + Loading Loading
recipes-kernel/linux/linux-xlnx/vsc3304.patch +300 −34 Original line number Diff line number Diff line Index: git/drivers/misc/Kconfig =================================================================== --- git.orig/drivers/misc/Kconfig 2013-12-02 23:08:01.002329798 -0700 +++ git/drivers/misc/Kconfig 2013-12-02 23:08:03.994329829 -0700 --- git.orig/drivers/misc/Kconfig 2013-12-03 15:26:18.686938629 -0700 +++ git/drivers/misc/Kconfig 2013-12-03 15:26:21.590938659 -0700 @@ -549,6 +549,19 @@ their requirements. Loading @@ -24,8 +24,8 @@ Index: git/drivers/misc/Kconfig source "drivers/misc/eeprom/Kconfig" Index: git/drivers/misc/Makefile =================================================================== --- git.orig/drivers/misc/Makefile 2013-12-02 23:08:01.002329798 -0700 +++ git/drivers/misc/Makefile 2013-12-02 23:08:03.994329829 -0700 --- git.orig/drivers/misc/Makefile 2013-12-03 15:26:18.686938629 -0700 +++ git/drivers/misc/Makefile 2013-12-03 15:26:21.590938659 -0700 @@ -55,3 +55,5 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o Loading @@ -35,7 +35,7 @@ Index: git/drivers/misc/Makefile Index: git/drivers/misc/vsc330x.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ git/drivers/misc/vsc330x.c 2013-12-02 23:08:03.998329829 -0700 +++ git/drivers/misc/vsc330x.c 2013-12-03 15:26:21.594938659 -0700 @@ -0,0 +1,872 @@ +/*!*************************************************************************** + *! FILE NAME : vsc330x.c Loading Loading @@ -912,8 +912,8 @@ Index: git/drivers/misc/vsc330x.c Index: git/drivers/misc/si5338.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ git/drivers/misc/si5338.c 2013-12-02 23:17:35.422335756 -0700 @@ -0,0 +1,1493 @@ +++ git/drivers/misc/si5338.c 2013-12-03 22:08:01.215188627 -0700 @@ -0,0 +1,1759 @@ +/*!*************************************************************************** + *! FILE NAME : si5338.c + *! DESCRIPTION: control of the Silicon Laboratories SI5338 clock generator Loading Loading @@ -986,6 +986,8 @@ Index: git/drivers/misc/si5338.c +#define AWE_VCO_GAIN 0x3170 +#define AWE_RSEL 0x310c +#define AWE_BWSEL 0x3103 +#define AWE_VCO_GAIN_RSEL_BWSEL 0x317f + +#define AWE_PLL_EN 0x32c0 +#define AWE_MSCAL 0x323f +#define AWE_MS3_HS 0x3380 Loading Loading @@ -1071,6 +1073,13 @@ Index: git/drivers/misc/si5338.c +#define AWE_MSN_P3_23_16 0x69ff +#define AWE_MSN_P3_29_24 0x6a3f + +#define AWE_MISC_47 0x2ffc /* write 0x5 */ +#define AWE_MISC_106 0x6a80 /* write 0x1 */ +#define AWE_MISC_116 0x7480 /* write 0x1 */ +#define AWE_MISC_42 0x2a20 /* write 0x1 */ +#define AWE_MISC_06A 0x06e0 /* write 0x0 */ +#define AWE_MISC_06B 0x0602 /* write 0x0 */ +#define AWE_MISC_28 0x1cc0 /* write 0x0 */ + +static void si5338_init_of(struct i2c_client *client); + Loading Loading @@ -1142,9 +1151,25 @@ Index: git/drivers/misc/si5338.c +static ssize_t pll_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_by_out_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_by_out_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t _pll_ms_freq_show(struct device *dev, struct device_attribute *attr, char *buf, int chn); +static ssize_t _pll_ms_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,int int_div, int chn); +static ssize_t pll_ms0_freq_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t pll_ms1_freq_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t pll_ms2_freq_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t pll_ms3_freq_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t pll_ms0_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms1_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms2_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms3_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms0_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms1_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms2_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t pll_ms3_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); + + +/* -------------------------------------- */ +static int set_pll_paremeters(struct i2c_client *client); +static int set_misc_registers(struct i2c_client *client); +static int ms_to_p123(u64* ms,u32 * p123); +static int p123_to_ms(u64* ms,u32 * p123); +static int get_ms_p123(struct i2c_client *client,u32 * p123, int chn); /* chn 0,1,2,3,4 (4 - msn) */ Loading @@ -1153,7 +1178,8 @@ Index: git/drivers/misc/si5338.c +static int get_pll_freq(struct i2c_client *client,u64 * pll_freq); +static int set_pll_freq_by_out(struct i2c_client *client, u64 *out_freq, int int_msn_div); + + +static int get_pll_ms_freq(struct i2c_client *client, u64 *out_freq, int chn); +static int set_pll_ms_by_out(struct i2c_client *client, u64 *out_freq, int chn, int int_div); +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); Loading Loading @@ -1273,12 +1299,30 @@ Index: git/drivers/misc/si5338.c +static DEVICE_ATTR(pll_by_out_int, SYSFS_PERMISSIONS, pll_freq_show, pll_by_out_int_store); + + +static DEVICE_ATTR(pll_ms0_freq_fract,SYSFS_PERMISSIONS, pll_ms0_freq_show, pll_ms0_freq_fract_store); +static DEVICE_ATTR(pll_ms0_freq_int, SYSFS_PERMISSIONS, pll_ms0_freq_show, pll_ms0_freq_int_store); +static DEVICE_ATTR(pll_ms1_freq_fract,SYSFS_PERMISSIONS, pll_ms1_freq_show, pll_ms1_freq_fract_store); +static DEVICE_ATTR(pll_ms1_freq_int, SYSFS_PERMISSIONS, pll_ms1_freq_show, pll_ms1_freq_int_store); +static DEVICE_ATTR(pll_ms2_freq_fract,SYSFS_PERMISSIONS, pll_ms2_freq_show, pll_ms2_freq_fract_store); +static DEVICE_ATTR(pll_ms2_freq_int, SYSFS_PERMISSIONS, pll_ms2_freq_show, pll_ms2_freq_int_store); +static DEVICE_ATTR(pll_ms3_freq_fract,SYSFS_PERMISSIONS, pll_ms3_freq_show, pll_ms3_freq_fract_store); +static DEVICE_ATTR(pll_ms3_freq_int, SYSFS_PERMISSIONS, pll_ms3_freq_show, pll_ms3_freq_int_store); + + +static struct attribute *pll_dev_attrs[] = { + &dev_attr_pll_ref_frequency.attr, + &dev_attr_pll_freq_fract.attr, + &dev_attr_pll_freq_int.attr, + &dev_attr_pll_by_out_fract.attr, + &dev_attr_pll_by_out_int.attr, + &dev_attr_pll_ms0_freq_fract.attr, + &dev_attr_pll_ms0_freq_int.attr, + &dev_attr_pll_ms1_freq_fract.attr, + &dev_attr_pll_ms1_freq_int.attr, + &dev_attr_pll_ms2_freq_fract.attr, + &dev_attr_pll_ms2_freq_int.attr, + &dev_attr_pll_ms3_freq_fract.attr, + &dev_attr_pll_ms3_freq_int.attr, + NULL +}; + Loading Loading @@ -1439,22 +1483,7 @@ Index: git/drivers/misc/si5338.c + mutex_unlock(&clientdata->lock); + 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"}; Loading Loading @@ -1734,8 +1763,13 @@ Index: git/drivers/misc/si5338.c + } + if (by_out) { + if (((rc=set_pll_freq_by_out(client, freq, int_div)))<0) return rc; + if (((rc=set_pll_paremeters(client)))<0) return rc; + if (((rc=set_misc_registers(client)))<0) return rc; + + } else { + if (((rc=set_pll_freq (client, freq, int_div)))<0) return rc; + if (((rc=set_pll_paremeters(client)))<0) return rc; + if (((rc=set_misc_registers(client)))<0) return rc; + } + return count; +} Loading @@ -1748,14 +1782,129 @@ Index: git/drivers/misc/si5338.c +static ssize_t pll_by_out_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) + {return _pll_freq_store(dev, attr, buf, count, 1, 1);} + +static ssize_t _pll_ms_freq_show(struct device *dev, struct device_attribute *attr, char *buf, int chn) +{ + int rc; + u64 ms_freq[3]; + struct i2c_client *client = to_i2c_client(dev); + + if (((rc=get_pll_ms_freq(client, ms_freq, chn)))<0) return rc; + return sprintf(buf, "%lld %lld %lld\n",ms_freq[0],ms_freq[1],ms_freq[2]); +} +static ssize_t _pll_ms_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,int int_div, int chn) +{ + struct i2c_client *client = to_i2c_client(dev); + int rc; + u64 freq[3]; + int num_items; + num_items=sscanf(buf, "%lld %lld %lld", &freq[0], &freq[1], &freq[2]); + if (num_items<3){ + freq[1]=0; + freq[2]=1; + } + if (((rc=set_pll_ms_by_out(client, freq, chn, int_div)))<0) return rc; + return count; +} +static ssize_t pll_ms0_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{return _pll_ms_freq_show(dev, attr, buf, 0);} +static ssize_t pll_ms1_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{return _pll_ms_freq_show(dev, attr, buf, 1);} +static ssize_t pll_ms2_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{return _pll_ms_freq_show(dev, attr, buf, 2);} +static ssize_t pll_ms3_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{return _pll_ms_freq_show(dev, attr, buf, 3);} +static ssize_t pll_ms0_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 0, 0);} +static ssize_t pll_ms1_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 0, 1);} +static ssize_t pll_ms2_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 0, 2);} +static ssize_t pll_ms3_freq_fract_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 0, 3);} +static ssize_t pll_ms0_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 1, 0);} +static ssize_t pll_ms1_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 1, 1);} +static ssize_t pll_ms2_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 1, 2);} +static ssize_t pll_ms3_freq_int_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{return _pll_ms_freq_store(dev, attr, buf, count, 1, 3);} + + +/* -----------PLL section--------------------------- */ +/* Setting PLL frequency in 3 ways: + * 1 - specified directly, allow fractional MSN + * 2 - specified directly, integer MSN + * 3 - specified by output frequency, integer MSN + */ +static int set_pll_paremeters(struct i2c_client *client) +{ + int rc; + s64 pll_in_freq; + u64 pll_out_freq[3]; + s64 K,Q,kphi_nom,kphi_denom,fvco_mhz, fpfd_mhz; + int rsel,bwsel,vco_gain,pll_kphi,mscal,ms_pec; + if (((pll_in_freq=get_pll_in_frequency(client)))<0) return (int) pll_in_freq; + if (((rc=get_pll_freq(client,pll_out_freq)))<0) return rc; + fpfd_mhz = div64_u64(pll_in_freq,1000000ll); + fvco_mhz = div64_u64(pll_out_freq[0],1000000ll); + if (fpfd_mhz>=15){ + K=925; + rsel=0; + bwsel=0; + } else if (fpfd_mhz>=8){ + K=325; + rsel=1; + bwsel=1; + } else { + K=185; + rsel=3; + bwsel=2; + } + if (fvco_mhz>2425){ + Q=3; + vco_gain=0; + } else { + Q=4; + vco_gain=1; + } + kphi_nom= K*2500LL*2500LL*2500LL; + kphi_denom=533LL*Q*fpfd_mhz*fvco_mhz*fvco_mhz; + pll_kphi=(int) div64_u64(kphi_nom + (kphi_denom>>1),kphi_denom); + if ((pll_kphi<1) || (pll_kphi>127)) { + dev_err(&client->dev, "Calculated PLL_KPHI does not fit 1<=%d<=127\n",pll_kphi); + if (pll_kphi<1) pll_kphi=1; + else if (pll_kphi>127) pll_kphi=127; + } + mscal = (int) div64_u64(2067000-667*fvco_mhz+50000,100000ll); + if ((mscal<0) || (mscal>63)) { + dev_err(&client->dev, "Calculated MSCAL does not fit 0<=%d<=63\n",mscal); + if (mscal<0) mscal=0; + else if (mscal>63) mscal=63; + } + ms_pec = 7; + dev_dbg(&client->dev, "Calculated values: PLL_KPHI=%d K=%lld RSEL=%d BWSEL=%d VCO_GAIN=%d MSCAL=%d MS_PEC=%d\n", + pll_kphi, K, rsel, bwsel, vco_gain, mscal, ms_pec); + /* setting actual registers */ + if (((rc=write_field(client, (u8) pll_kphi, AWE_PLL_KPHI)))<0) return rc; + if (((rc=write_field(client, (u8) (((vco_gain & 7)<<4) | ((rsel & 3)<<2) | (bwsel & 3)), + AWE_VCO_GAIN_RSEL_BWSEL)))<0) return rc; + if (((rc=write_field(client, (u8) mscal, AWE_MSCAL )))<0) return rc; + if (((rc=write_field(client, (u8) ms_pec, AWE_MS_PEC)))<0) return rc; + return 0; +} + +static int set_misc_registers(struct i2c_client *client) +{ + /* ST52238 Reference Manual R1.2 p.28 */ + int rc; + if (((rc=write_field(client, 0x5, AWE_MISC_47 )))<0) return rc; + if (((rc=write_field(client, 0x1, AWE_MISC_106 )))<0) return rc; + if (((rc=write_field(client, 0x1, AWE_MISC_116 )))<0) return rc; + if (((rc=write_field(client, 0x1, AWE_MISC_42 )))<0) return rc; + if (((rc=write_field(client, 0x0, AWE_MISC_06A )))<0) return rc; + if (((rc=write_field(client, 0x0, AWE_MISC_06B )))<0) return rc; + if (((rc=write_field(client, 0x0, AWE_MISC_28 )))<0) return rc; + return 0; +} + + +/* -----------MultiSynth section--------------------------- */ +static u32 awe_msx[5][3][5]= + {{{AWE_MS0_P1_07_00, AWE_MS0_P1_15_08, AWE_MS0_P1_17_16, 0, 0}, + {AWE_MS0_P2_05_00, AWE_MS0_P2_13_06, AWE_MS0_P2_21_14, AWE_MS0_P2_29_22, 0}, Loading Loading @@ -1824,6 +1973,10 @@ Index: git/drivers/misc/si5338.c +{ + int i; + s64 rc; + if ((chn<0) || (chn>4)){ + dev_err(&client->dev, "Invalid channel %d. Only 0,1,2,3 and 4 (for MSN) are supported\n",chn); + return - EINVAL; + } + for (i=0;i<3;i++){ + if (((rc=read_multireg64 (client, awe_msx[chn][i])))<0) return (int) rc; + p123[i]= (u32) rc; Loading @@ -1833,12 +1986,22 @@ Index: git/drivers/misc/si5338.c +static int set_ms_p123(struct i2c_client *client,u32 * p123, int chn) /* chn 0,1,2,3,4 (4 - msn) */ +{ + int i,rc; + if ((chn<0) || (chn>4)){ + dev_err(&client->dev, "Invalid channel %d. Only 0,1,2,3 and 4 (for MSN) are supported\n",chn); + return - EINVAL; + } + for (i=0;i<3;i++){ + if (((rc=write_multireg64(client, (u64) p123[i], awe_msx[chn][i])))<0) return rc; + } + return 0; +} + +/* Setting PLL frequency in 3 ways: + * 1 - specified directly, allow fractional MSN + * 2 - specified directly, integer MSN + * 3 - specified by output frequency, allow fractional MSN (use PPL frequency closest to the middle) + * 4 - specified by output frequency, integer MSN + */ +static int set_pll_freq(struct i2c_client *client, u64 *vco_freq, int int_div) +{ + s64 pll_in_freq, pll_in_freq_scaled,pll_out_freq_scaled,d; Loading Loading @@ -1892,7 +2055,7 @@ Index: git/drivers/misc/si5338.c + ms_to_p123(msn, msn_p123); + return set_ms_p123(client,msn_p123, 4); // MSN +} + +/* normalizes output */ +static int get_pll_freq(struct i2c_client *client,u64 * pll_freq) +{ + int rc; Loading Loading @@ -1924,15 +2087,20 @@ Index: git/drivers/misc/si5338.c +{ + /* use r-divider if the output frequency is too low (less than 5 MHz) */ + u64 out_int=out_freq[0],out_nom=out_freq[1],out_denom=out_freq[2], + pll_out_freq[3], scaled_max,scaled_min; + pll_out_freq[3], scaled_max,scaled_min,d; + s64 pll_freq_scaled, out_freq_scaled,err,best_err=-1,out_div,pll_in_freq,in_div,best_in_div, + pll_in_freq_scaled,synth_out_scaled; + int r_div=1; + if (out_denom<out_nom){ + dev_err(&client->dev, "Nominator (%lld) should be less than denominator (%lld)\n", + out_nom,out_denom); + if (out_denom==0){ + dev_err(&client->dev, "Denominator should not be 0 in %lld+%lld/%lld\n", + out_int,out_nom,out_denom); + return -EINVAL; + } + if (out_nom>=out_denom){ /* normalize */ + d=div64_u64(out_nom,out_denom); + out_int+=d; + out_nom-=d*out_denom; + } + if (out_int<(FVCOMAX/MSINT_MAX)){ + while ((r_div < 32) && (out_int<(FVCOMAX/MSINT_MAX))){ + out_int<<=1; Loading Loading @@ -2014,8 +2182,106 @@ Index: git/drivers/misc/si5338.c + return set_pll_freq(client, pll_out_freq, 0); /* integer result */ + } +} +static int get_pll_ms_freq(struct i2c_client *client, u64 *out_freq, int chn) +{ + int rc; + u64 pll_out_freq[3], ms[3], pll_freq_scaled, ms_scaled; + u32 p123[3]; + if (((rc=get_pll_freq(client,pll_out_freq)))<0) return rc; + /* trim PLL frequency fraction */ + while (pll_out_freq[2]>=0x1000){ + pll_out_freq[1] >>= 1; + pll_out_freq[2] >>= 1; + } + pll_freq_scaled=pll_out_freq[0]*pll_out_freq[2]+pll_out_freq[1]; + + if (((rc=get_ms_p123(client,p123, chn)))<0) return rc; /* includes invalid chn */ + p123_to_ms(ms,p123); + /* trim MS divisor fraction */ + while (ms[2]>=0x1000){ + ms[1] >>= 1; + ms[2] >>= 1; + } + ms_scaled=ms[0]*ms[2]+ms[1]; + out_freq[1]=pll_freq_scaled*ms[2]; + out_freq[2]=ms[0]*pll_out_freq[2]; + out_freq[0]=div64_u64(out_freq[1],out_freq[2]); + out_freq[1]-=out_freq[0]*out_freq[2]; + dev_dbg(&client->dev, "MS%d output frequency: %llu+%llu/%llu Hz\n",chn,out_freq[0],out_freq[1],out_freq[2]); + return 0; +} + +/* + * Adjust MultiSynth divisor (MS0..MS3) for specified output frequency + * MSN, input frequency should be already set + * out_freq as int,nom,denom + */ +static int set_pll_ms_by_out(struct i2c_client *client, u64 *out_freq, int chn, int int_div) +{ + /* use r-divider if the output frequency is too low (less than 5 MHz) */ + u64 out_int=out_freq[0],out_nom=out_freq[1],out_denom=out_freq[2], + pll_out_freq[3],d; + s64 pll_freq_scaled, out_freq_scaled; + u64 ms[3]; + u32 p123[3]; + int r_div=1,rc; + if (out_denom==0){ + dev_err(&client->dev, "Denominator should not be 0 in %lld+%lld/%lld\n", + out_int,out_nom,out_denom); + return -EINVAL; + } + if (out_nom>=out_denom){ /* normalize */ + d=div64_u64(out_nom,out_denom); + out_int+=d; + out_nom-=d*out_denom; + } + if (out_int<(FVCOMAX/MSINT_MAX)){ + while ((r_div < 32) && (out_int<(FVCOMAX/MSINT_MAX))){ + out_int<<=1; + out_nom<<=1; + r_div<<=1; + if (out_nom>out_denom) { + out_int++; + out_nom-=out_denom; + } + + } + if (out_int<(FVCOMAX/MSINT_MAX)){ + dev_err(&client->dev, "Specified output frequency is too low: %lld < %lld\n", + out_freq[0], FVCOMAX/MSINT_MAX/32); + return -EINVAL; + } + } + dev_dbg(&client->dev, "Output divider by %u, Output frequency before divider: %llu+%llu/%llu Hz\n", + r_div,out_int, out_nom,out_denom); + /* trim output frequency fraction */ + while (out_denom>=0x1000){ + out_nom >>= 1; + out_denom >>= 1; + } + out_freq_scaled=out_int*out_denom+out_nom; + if (((rc=get_pll_freq(client,pll_out_freq)))<0) return rc; + /* trim PLL frequency fraction */ + while (pll_out_freq[2]>=0x1000){ + pll_out_freq[1] >>= 1; + pll_out_freq[2] >>= 1; + } + pll_freq_scaled=pll_out_freq[0]*pll_out_freq[2]+pll_out_freq[1]; + ms[1]=pll_freq_scaled*out_denom; + ms[2]=out_freq_scaled*pll_out_freq[2]; + ms[0]=div64_u64(ms[1],ms[2]); + ms[1]-=ms[0]*ms[2]; + if (int_div){ + if (ms[1]>(ms[2]>>1)) ms[0]++; + ms[1]=0; + ms[2]=1; + } + dev_dbg(&client->dev, "MS%d divider: %llu+%llu/%llu\n",chn,ms[0],ms[1],ms[2]); + /* set up registers */ + ms_to_p123(ms,p123); + if (((rc=set_ms_p123(client,p123, chn)))<0) return rc; + return 0; +} + +/* ----------- Input section ----------------- */ + Loading