2015-06-08 05:44:51

by Sanchayan

[permalink] [raw]
Subject: [PATCH v1 0/2] Implement sample time consideration

Hello,

This patchset adds a dt binding for specifying sample time
for the vybrid adc driver and takes this into account for
sampling frequency calculation and related configuration in
the driver.

The patchset is based on top of Stefan's patches here
http://lkml.iu.edu/hypermail/linux/kernel/1505.3/02043.html

which got recently applied. Tested with shawn's for-next
branch.

Regards,
Sanchayan.

Sanchayan Maity (2):
iio: adc: Determine sampling frequencies by using minimum sample time
ARM: dts: vfxxx: Add property for minimum sample time

.../devicetree/bindings/iio/adc/vf610-adc.txt | 6 ++
arch/arm/boot/dts/vfxxx.dtsi | 2 +
drivers/iio/adc/vf610_adc.c | 74 ++++++++++++++++++++--
3 files changed, 78 insertions(+), 4 deletions(-)

--
2.4.2


2015-06-08 05:45:12

by Sanchayan

[permalink] [raw]
Subject: [PATCH v1 1/2] iio: adc: Determine sampling frequencies by using minimum sample time

The driver currently does not take into account the minimum sample time
as per the Figure 6-8 Chapter 9.1.1 12-bit ADC electrical characteristics.
We set a static amount of cycles instead of considering the sample time as
a given value, which depends on hardware characteristics.

Determine sampling frequencies by first reading the device tree property
node and then calculating the required Long Sample Time Adder (LSTAdder)
value based on the ADC clock frequency and sample time value obtained
from the device tree, this LSTAdder value is then used for calculating
the sampling frequencies possible.

Signed-off-by: Sanchayan Maity <[email protected]>
---
.../devicetree/bindings/iio/adc/vf610-adc.txt | 6 ++
drivers/iio/adc/vf610_adc.c | 74 ++++++++++++++++++++--
2 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
index 3eb40e2..4419126 100644
--- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
@@ -17,6 +17,11 @@ Recommended properties:
- Frequency in normal mode (ADLPC=0, ADHSC=0)
- Frequency in high-speed mode (ADLPC=0, ADHSC=1)
- Frequency in low-power mode (ADLPC=1, ADHSC=0)
+ - fsl,min-sample-time: Minimum sampling time in nanoseconds. This value has
+ to be chosen according to the conversion mode and the connected analog
+ source resistance (R_as) and capacitance (C_as). Refer the datasheet's
+ operating requirements. A safe default across a wide range of R_as and
+ C_as as well as conversion modes is 1000ns.

Example:
adc0: adc@4003b000 {
@@ -27,5 +32,6 @@ adc0: adc@4003b000 {
clock-names = "adc";
fsl,adck-max-frequency = <30000000>, <40000000>,
<20000000>;
+ fsl,min-sample-time = <1000>;
vref-supply = <&reg_vcc_3v3_mcu>;
};
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 480f335..bcae8fd 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -68,6 +68,9 @@
#define VF610_ADC_CLK_DIV8 0x60
#define VF610_ADC_CLK_MASK 0x60
#define VF610_ADC_ADLSMP_LONG 0x10
+#define VF610_ADC_ADSTS_SHORT 0x100
+#define VF610_ADC_ADSTS_NORMAL 0x200
+#define VF610_ADC_ADSTS_LONG 0x300
#define VF610_ADC_ADSTS_MASK 0x300
#define VF610_ADC_ADLPC_EN 0x80
#define VF610_ADC_ADHSC_EN 0x400
@@ -124,6 +127,17 @@ enum conversion_mode_sel {
VF610_ADC_CONV_LOW_POWER,
};

+enum lst_adder_sel {
+ VF610_ADCK_CYCLES_3,
+ VF610_ADCK_CYCLES_5,
+ VF610_ADCK_CYCLES_7,
+ VF610_ADCK_CYCLES_9,
+ VF610_ADCK_CYCLES_13,
+ VF610_ADCK_CYCLES_17,
+ VF610_ADCK_CYCLES_21,
+ VF610_ADCK_CYCLES_25,
+};
+
struct vf610_adc_feature {
enum clk_sel clk_sel;
enum vol_ref vol_ref;
@@ -132,6 +146,8 @@ struct vf610_adc_feature {
int clk_div;
int sample_rate;
int res_mode;
+ u32 lst_adder_index;
+ u32 default_sample_time;

bool calibration;
bool ovwren;
@@ -155,11 +171,13 @@ struct vf610_adc {
};

static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
+static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 };

static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &info->adc_feature;
unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
+ u32 adck_period, lst_addr_min;
int divisor, i;

adck_rate = info->max_adck_rate[adc_feature->conv_mode];
@@ -174,6 +192,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
}

/*
+ * Determine the long sample time adder value to be used based
+ * on the default minimum sample time provided.
+ */
+ adck_period = NSEC_PER_SEC / adck_rate;
+ lst_addr_min = adc_feature->default_sample_time / adck_period;
+ for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) {
+ if (vf610_lst_adder[i] > lst_addr_min) {
+ adc_feature->lst_adder_index = i;
+ break;
+ }
+ }
+
+ /*
* Calculate ADC sample frequencies
* Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
* which is the same as bus clock.
@@ -182,12 +213,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
* SFCAdder: fixed to 6 ADCK cycles
* AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
* BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
- * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
+ * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles
*/
adck_rate = ipg_rate / info->adc_feature.clk_div;
for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
info->sample_freq_avail[i] =
- adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
+ adck_rate / (6 + vf610_hw_avgs[i] *
+ (25 + vf610_lst_adder[adc_feature->lst_adder_index]));
}

static inline void vf610_adc_cfg_init(struct vf610_adc *info)
@@ -347,8 +379,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info)
break;
}

- /* Use the short sample mode */
- cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
+ /*
+ * Set ADLSMP and ADSTS based on the Long Sample Time Adder value
+ * determined.
+ */
+ switch (adc_feature->lst_adder_index) {
+ case VF610_ADCK_CYCLES_3:
+ break;
+ case VF610_ADCK_CYCLES_5:
+ cfg_data |= VF610_ADC_ADSTS_SHORT;
+ break;
+ case VF610_ADCK_CYCLES_7:
+ cfg_data |= VF610_ADC_ADSTS_NORMAL;
+ break;
+ case VF610_ADCK_CYCLES_9:
+ cfg_data |= VF610_ADC_ADSTS_LONG;
+ break;
+ case VF610_ADCK_CYCLES_13:
+ cfg_data |= VF610_ADC_ADLSMP_LONG;
+ break;
+ case VF610_ADCK_CYCLES_17:
+ cfg_data |= VF610_ADC_ADLSMP_LONG;
+ cfg_data |= VF610_ADC_ADSTS_SHORT;
+ break;
+ case VF610_ADCK_CYCLES_21:
+ cfg_data |= VF610_ADC_ADLSMP_LONG;
+ cfg_data |= VF610_ADC_ADSTS_NORMAL;
+ break;
+ case VF610_ADCK_CYCLES_25:
+ cfg_data |= VF610_ADC_ADLSMP_LONG;
+ cfg_data |= VF610_ADC_ADSTS_NORMAL;
+ break;
+ default:
+ dev_err(info->dev, "error in sample time select\n");
+ }

/* update hardware average selection */
cfg_data &= ~VF610_ADC_AVGS_MASK;
@@ -712,6 +776,8 @@ static int vf610_adc_probe(struct platform_device *pdev)

of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency",
info->max_adck_rate, 3);
+ of_property_read_u32(pdev->dev.of_node, "fsl,min-sample-time",
+ &info->adc_feature.default_sample_time);

platform_set_drvdata(pdev, indio_dev);

--
2.4.2

2015-06-08 05:45:19

by Sanchayan

[permalink] [raw]
Subject: [PATCH v1 2/2] ARM: dts: vfxxx: Add property for minimum sample time

Add a device tree property which allows to specify the minimum sample
time which can be used to calculate the actual ADC cycles required
depending on the hardware.

Signed-off-by: Sanchayan Maity <[email protected]>
---
arch/arm/boot/dts/vfxxx.dtsi | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
index 90a03d5..463cfe3 100644
--- a/arch/arm/boot/dts/vfxxx.dtsi
+++ b/arch/arm/boot/dts/vfxxx.dtsi
@@ -229,6 +229,7 @@
status = "disabled";
fsl,adck-max-frequency = <30000000>, <40000000>,
<20000000>;
+ fsl,min-sample-time = <1000>;
};

wdoga5: wdog@4003e000 {
@@ -447,6 +448,7 @@
status = "disabled";
fsl,adck-max-frequency = <30000000>, <40000000>,
<20000000>;
+ fsl,min-sample-time = <1000>;
};

esdhc1: esdhc@400b2000 {
--
2.4.2

2015-06-08 17:52:04

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] iio: adc: Determine sampling frequencies by using minimum sample time

On Mon, Jun 8, 2015 at 12:42 AM, Sanchayan Maity
<[email protected]> wrote:
> The driver currently does not take into account the minimum sample time
> as per the Figure 6-8 Chapter 9.1.1 12-bit ADC electrical characteristics.
> We set a static amount of cycles instead of considering the sample time as
> a given value, which depends on hardware characteristics.
>
> Determine sampling frequencies by first reading the device tree property
> node and then calculating the required Long Sample Time Adder (LSTAdder)
> value based on the ADC clock frequency and sample time value obtained
> from the device tree, this LSTAdder value is then used for calculating
> the sampling frequencies possible.
>
> Signed-off-by: Sanchayan Maity <[email protected]>
> ---
> .../devicetree/bindings/iio/adc/vf610-adc.txt | 6 ++
> drivers/iio/adc/vf610_adc.c | 74 ++++++++++++++++++++--
> 2 files changed, 76 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
> index 3eb40e2..4419126 100644
> --- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
> +++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
> @@ -17,6 +17,11 @@ Recommended properties:
> - Frequency in normal mode (ADLPC=0, ADHSC=0)
> - Frequency in high-speed mode (ADLPC=0, ADHSC=1)
> - Frequency in low-power mode (ADLPC=1, ADHSC=0)
> + - fsl,min-sample-time: Minimum sampling time in nanoseconds. This value has

Add a "-ns' suffix.

Seems like this could be a common ADC property.

> + to be chosen according to the conversion mode and the connected analog
> + source resistance (R_as) and capacitance (C_as). Refer the datasheet's
> + operating requirements. A safe default across a wide range of R_as and
> + C_as as well as conversion modes is 1000ns.
>
> Example:
> adc0: adc@4003b000 {
> @@ -27,5 +32,6 @@ adc0: adc@4003b000 {
> clock-names = "adc";
> fsl,adck-max-frequency = <30000000>, <40000000>,
> <20000000>;
> + fsl,min-sample-time = <1000>;
> vref-supply = <&reg_vcc_3v3_mcu>;
> };
> diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
> index 480f335..bcae8fd 100644
> --- a/drivers/iio/adc/vf610_adc.c
> +++ b/drivers/iio/adc/vf610_adc.c
> @@ -68,6 +68,9 @@
> #define VF610_ADC_CLK_DIV8 0x60
> #define VF610_ADC_CLK_MASK 0x60
> #define VF610_ADC_ADLSMP_LONG 0x10
> +#define VF610_ADC_ADSTS_SHORT 0x100
> +#define VF610_ADC_ADSTS_NORMAL 0x200
> +#define VF610_ADC_ADSTS_LONG 0x300
> #define VF610_ADC_ADSTS_MASK 0x300
> #define VF610_ADC_ADLPC_EN 0x80
> #define VF610_ADC_ADHSC_EN 0x400
> @@ -124,6 +127,17 @@ enum conversion_mode_sel {
> VF610_ADC_CONV_LOW_POWER,
> };
>
> +enum lst_adder_sel {
> + VF610_ADCK_CYCLES_3,
> + VF610_ADCK_CYCLES_5,
> + VF610_ADCK_CYCLES_7,
> + VF610_ADCK_CYCLES_9,
> + VF610_ADCK_CYCLES_13,
> + VF610_ADCK_CYCLES_17,
> + VF610_ADCK_CYCLES_21,
> + VF610_ADCK_CYCLES_25,
> +};
> +
> struct vf610_adc_feature {
> enum clk_sel clk_sel;
> enum vol_ref vol_ref;
> @@ -132,6 +146,8 @@ struct vf610_adc_feature {
> int clk_div;
> int sample_rate;
> int res_mode;
> + u32 lst_adder_index;
> + u32 default_sample_time;
>
> bool calibration;
> bool ovwren;
> @@ -155,11 +171,13 @@ struct vf610_adc {
> };
>
> static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
> +static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 };
>
> static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
> {
> struct vf610_adc_feature *adc_feature = &info->adc_feature;
> unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
> + u32 adck_period, lst_addr_min;
> int divisor, i;
>
> adck_rate = info->max_adck_rate[adc_feature->conv_mode];
> @@ -174,6 +192,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
> }
>
> /*
> + * Determine the long sample time adder value to be used based
> + * on the default minimum sample time provided.
> + */
> + adck_period = NSEC_PER_SEC / adck_rate;
> + lst_addr_min = adc_feature->default_sample_time / adck_period;
> + for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) {
> + if (vf610_lst_adder[i] > lst_addr_min) {
> + adc_feature->lst_adder_index = i;
> + break;
> + }
> + }
> +
> + /*
> * Calculate ADC sample frequencies
> * Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
> * which is the same as bus clock.
> @@ -182,12 +213,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
> * SFCAdder: fixed to 6 ADCK cycles
> * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
> * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
> - * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
> + * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles
> */
> adck_rate = ipg_rate / info->adc_feature.clk_div;
> for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
> info->sample_freq_avail[i] =
> - adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
> + adck_rate / (6 + vf610_hw_avgs[i] *
> + (25 + vf610_lst_adder[adc_feature->lst_adder_index]));
> }
>
> static inline void vf610_adc_cfg_init(struct vf610_adc *info)
> @@ -347,8 +379,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info)
> break;
> }
>
> - /* Use the short sample mode */
> - cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
> + /*
> + * Set ADLSMP and ADSTS based on the Long Sample Time Adder value
> + * determined.
> + */
> + switch (adc_feature->lst_adder_index) {
> + case VF610_ADCK_CYCLES_3:
> + break;
> + case VF610_ADCK_CYCLES_5:
> + cfg_data |= VF610_ADC_ADSTS_SHORT;
> + break;
> + case VF610_ADCK_CYCLES_7:
> + cfg_data |= VF610_ADC_ADSTS_NORMAL;
> + break;
> + case VF610_ADCK_CYCLES_9:
> + cfg_data |= VF610_ADC_ADSTS_LONG;
> + break;
> + case VF610_ADCK_CYCLES_13:
> + cfg_data |= VF610_ADC_ADLSMP_LONG;
> + break;
> + case VF610_ADCK_CYCLES_17:
> + cfg_data |= VF610_ADC_ADLSMP_LONG;
> + cfg_data |= VF610_ADC_ADSTS_SHORT;
> + break;
> + case VF610_ADCK_CYCLES_21:
> + cfg_data |= VF610_ADC_ADLSMP_LONG;
> + cfg_data |= VF610_ADC_ADSTS_NORMAL;
> + break;
> + case VF610_ADCK_CYCLES_25:
> + cfg_data |= VF610_ADC_ADLSMP_LONG;
> + cfg_data |= VF610_ADC_ADSTS_NORMAL;
> + break;
> + default:
> + dev_err(info->dev, "error in sample time select\n");
> + }
>
> /* update hardware average selection */
> cfg_data &= ~VF610_ADC_AVGS_MASK;
> @@ -712,6 +776,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
>
> of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency",
> info->max_adck_rate, 3);
> + of_property_read_u32(pdev->dev.of_node, "fsl,min-sample-time",
> + &info->adc_feature.default_sample_time);
>
> platform_set_drvdata(pdev, indio_dev);
>
> --
> 2.4.2
>

2015-06-14 11:16:18

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] iio: adc: Determine sampling frequencies by using minimum sample time

On 08/06/15 18:51, Rob Herring wrote:
> On Mon, Jun 8, 2015 at 12:42 AM, Sanchayan Maity
> <[email protected]> wrote:
>> The driver currently does not take into account the minimum sample time
>> as per the Figure 6-8 Chapter 9.1.1 12-bit ADC electrical characteristics.
>> We set a static amount of cycles instead of considering the sample time as
>> a given value, which depends on hardware characteristics.
>>
>> Determine sampling frequencies by first reading the device tree property
>> node and then calculating the required Long Sample Time Adder (LSTAdder)
>> value based on the ADC clock frequency and sample time value obtained
>> from the device tree, this LSTAdder value is then used for calculating
>> the sampling frequencies possible.
>>
>> Signed-off-by: Sanchayan Maity <[email protected]>
>> ---
>> .../devicetree/bindings/iio/adc/vf610-adc.txt | 6 ++
>> drivers/iio/adc/vf610_adc.c | 74 ++++++++++++++++++++--
>> 2 files changed, 76 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
>> index 3eb40e2..4419126 100644
>> --- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
>> +++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
>> @@ -17,6 +17,11 @@ Recommended properties:
>> - Frequency in normal mode (ADLPC=0, ADHSC=0)
>> - Frequency in high-speed mode (ADLPC=0, ADHSC=1)
>> - Frequency in low-power mode (ADLPC=1, ADHSC=0)
>> + - fsl,min-sample-time: Minimum sampling time in nanoseconds. This value has
>
> Add a "-ns' suffix.
>
> Seems like this could be a common ADC property.
Could be but so far this is a first I think...

Obviously there are constraints on when you'll get a 'good' answer from any
ADC but often they are not so well defined in the datasheets as we have here.

Having said that, certainly could turn up elsewhere so I've no problem with
having it as normal (non vendor specific) property.
>
>> + to be chosen according to the conversion mode and the connected analog
>> + source resistance (R_as) and capacitance (C_as). Refer the datasheet's
>> + operating requirements. A safe default across a wide range of R_as and
>> + C_as as well as conversion modes is 1000ns.
>>
>> Example:
>> adc0: adc@4003b000 {
>> @@ -27,5 +32,6 @@ adc0: adc@4003b000 {
>> clock-names = "adc";
>> fsl,adck-max-frequency = <30000000>, <40000000>,
>> <20000000>;
>> + fsl,min-sample-time = <1000>;
>> vref-supply = <&reg_vcc_3v3_mcu>;
>> };
>> diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
>> index 480f335..bcae8fd 100644
>> --- a/drivers/iio/adc/vf610_adc.c
>> +++ b/drivers/iio/adc/vf610_adc.c
>> @@ -68,6 +68,9 @@
>> #define VF610_ADC_CLK_DIV8 0x60
>> #define VF610_ADC_CLK_MASK 0x60
>> #define VF610_ADC_ADLSMP_LONG 0x10
>> +#define VF610_ADC_ADSTS_SHORT 0x100
>> +#define VF610_ADC_ADSTS_NORMAL 0x200
>> +#define VF610_ADC_ADSTS_LONG 0x300
>> #define VF610_ADC_ADSTS_MASK 0x300
>> #define VF610_ADC_ADLPC_EN 0x80
>> #define VF610_ADC_ADHSC_EN 0x400
>> @@ -124,6 +127,17 @@ enum conversion_mode_sel {
>> VF610_ADC_CONV_LOW_POWER,
>> };
>>
>> +enum lst_adder_sel {
>> + VF610_ADCK_CYCLES_3,
>> + VF610_ADCK_CYCLES_5,
>> + VF610_ADCK_CYCLES_7,
>> + VF610_ADCK_CYCLES_9,
>> + VF610_ADCK_CYCLES_13,
>> + VF610_ADCK_CYCLES_17,
>> + VF610_ADCK_CYCLES_21,
>> + VF610_ADCK_CYCLES_25,
>> +};
>> +
>> struct vf610_adc_feature {
>> enum clk_sel clk_sel;
>> enum vol_ref vol_ref;
>> @@ -132,6 +146,8 @@ struct vf610_adc_feature {
>> int clk_div;
>> int sample_rate;
>> int res_mode;
>> + u32 lst_adder_index;
>> + u32 default_sample_time;
>>
>> bool calibration;
>> bool ovwren;
>> @@ -155,11 +171,13 @@ struct vf610_adc {
>> };
>>
>> static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
>> +static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 };
>>
>> static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
>> {
>> struct vf610_adc_feature *adc_feature = &info->adc_feature;
>> unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
>> + u32 adck_period, lst_addr_min;
>> int divisor, i;
>>
>> adck_rate = info->max_adck_rate[adc_feature->conv_mode];
>> @@ -174,6 +192,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
>> }
>>
>> /*
>> + * Determine the long sample time adder value to be used based
>> + * on the default minimum sample time provided.
>> + */
>> + adck_period = NSEC_PER_SEC / adck_rate;
>> + lst_addr_min = adc_feature->default_sample_time / adck_period;
>> + for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) {
>> + if (vf610_lst_adder[i] > lst_addr_min) {
>> + adc_feature->lst_adder_index = i;
>> + break;
>> + }
>> + }
>> +
>> + /*
>> * Calculate ADC sample frequencies
>> * Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
>> * which is the same as bus clock.
>> @@ -182,12 +213,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
>> * SFCAdder: fixed to 6 ADCK cycles
>> * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
>> * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
>> - * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
>> + * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles
>> */
>> adck_rate = ipg_rate / info->adc_feature.clk_div;
>> for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
>> info->sample_freq_avail[i] =
>> - adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
>> + adck_rate / (6 + vf610_hw_avgs[i] *
>> + (25 + vf610_lst_adder[adc_feature->lst_adder_index]));
>> }
>>
>> static inline void vf610_adc_cfg_init(struct vf610_adc *info)
>> @@ -347,8 +379,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info)
>> break;
>> }
>>
>> - /* Use the short sample mode */
>> - cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
>> + /*
>> + * Set ADLSMP and ADSTS based on the Long Sample Time Adder value
>> + * determined.
>> + */
>> + switch (adc_feature->lst_adder_index) {
>> + case VF610_ADCK_CYCLES_3:
>> + break;
>> + case VF610_ADCK_CYCLES_5:
>> + cfg_data |= VF610_ADC_ADSTS_SHORT;
>> + break;
>> + case VF610_ADCK_CYCLES_7:
>> + cfg_data |= VF610_ADC_ADSTS_NORMAL;
>> + break;
>> + case VF610_ADCK_CYCLES_9:
>> + cfg_data |= VF610_ADC_ADSTS_LONG;
>> + break;
>> + case VF610_ADCK_CYCLES_13:
>> + cfg_data |= VF610_ADC_ADLSMP_LONG;
>> + break;
>> + case VF610_ADCK_CYCLES_17:
>> + cfg_data |= VF610_ADC_ADLSMP_LONG;
>> + cfg_data |= VF610_ADC_ADSTS_SHORT;
>> + break;
>> + case VF610_ADCK_CYCLES_21:
>> + cfg_data |= VF610_ADC_ADLSMP_LONG;
>> + cfg_data |= VF610_ADC_ADSTS_NORMAL;
>> + break;
>> + case VF610_ADCK_CYCLES_25:
>> + cfg_data |= VF610_ADC_ADLSMP_LONG;
>> + cfg_data |= VF610_ADC_ADSTS_NORMAL;
>> + break;
>> + default:
>> + dev_err(info->dev, "error in sample time select\n");
>> + }
>>
>> /* update hardware average selection */
>> cfg_data &= ~VF610_ADC_AVGS_MASK;
>> @@ -712,6 +776,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
>>
>> of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency",
>> info->max_adck_rate, 3);
>> + of_property_read_u32(pdev->dev.of_node, "fsl,min-sample-time",
>> + &info->adc_feature.default_sample_time);
>>
>> platform_set_drvdata(pdev, indio_dev);
>>
>> --
>> 2.4.2
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

2015-06-17 10:36:10

by Sanchayan

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] iio: adc: Determine sampling frequencies by using minimum sample time

Hello,

On 15-06-14 12:16:07, Jonathan Cameron wrote:
> On 08/06/15 18:51, Rob Herring wrote:
> > On Mon, Jun 8, 2015 at 12:42 AM, Sanchayan Maity
> > <[email protected]> wrote:
> >> The driver currently does not take into account the minimum sample time
> >> as per the Figure 6-8 Chapter 9.1.1 12-bit ADC electrical characteristics.
> >> We set a static amount of cycles instead of considering the sample time as
> >> a given value, which depends on hardware characteristics.
> >>
> >> Determine sampling frequencies by first reading the device tree property
> >> node and then calculating the required Long Sample Time Adder (LSTAdder)
> >> value based on the ADC clock frequency and sample time value obtained
> >> from the device tree, this LSTAdder value is then used for calculating
> >> the sampling frequencies possible.
> >>
> >> Signed-off-by: Sanchayan Maity <[email protected]>
> >> ---
> >> .../devicetree/bindings/iio/adc/vf610-adc.txt | 6 ++
> >> drivers/iio/adc/vf610_adc.c | 74 ++++++++++++++++++++--
> >> 2 files changed, 76 insertions(+), 4 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
> >> index 3eb40e2..4419126 100644
> >> --- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
> >> +++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
> >> @@ -17,6 +17,11 @@ Recommended properties:
> >> - Frequency in normal mode (ADLPC=0, ADHSC=0)
> >> - Frequency in high-speed mode (ADLPC=0, ADHSC=1)
> >> - Frequency in low-power mode (ADLPC=1, ADHSC=0)
> >> + - fsl,min-sample-time: Minimum sampling time in nanoseconds. This value has
> >
> > Add a "-ns' suffix.
> >
> > Seems like this could be a common ADC property.
> Could be but so far this is a first I think...
>
> Obviously there are constraints on when you'll get a 'good' answer from any
> ADC but often they are not so well defined in the datasheets as we have here.
>
> Having said that, certainly could turn up elsewhere so I've no problem with
> having it as normal (non vendor specific) property.

Will change this to a non vendor specific property and send v2.

Thanks for the review.

Regards,
Sanchayan.

> >
> >> + to be chosen according to the conversion mode and the connected analog
> >> + source resistance (R_as) and capacitance (C_as). Refer the datasheet's
> >> + operating requirements. A safe default across a wide range of R_as and
> >> + C_as as well as conversion modes is 1000ns.
> >>
> >> Example:
> >> adc0: adc@4003b000 {
> >> @@ -27,5 +32,6 @@ adc0: adc@4003b000 {
> >> clock-names = "adc";
> >> fsl,adck-max-frequency = <30000000>, <40000000>,
> >> <20000000>;
> >> + fsl,min-sample-time = <1000>;
> >> vref-supply = <&reg_vcc_3v3_mcu>;
> >> };
> >> diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
> >> index 480f335..bcae8fd 100644
> >> --- a/drivers/iio/adc/vf610_adc.c
> >> +++ b/drivers/iio/adc/vf610_adc.c
> >> @@ -68,6 +68,9 @@
> >> #define VF610_ADC_CLK_DIV8 0x60
> >> #define VF610_ADC_CLK_MASK 0x60
> >> #define VF610_ADC_ADLSMP_LONG 0x10
> >> +#define VF610_ADC_ADSTS_SHORT 0x100
> >> +#define VF610_ADC_ADSTS_NORMAL 0x200
> >> +#define VF610_ADC_ADSTS_LONG 0x300
> >> #define VF610_ADC_ADSTS_MASK 0x300
> >> #define VF610_ADC_ADLPC_EN 0x80
> >> #define VF610_ADC_ADHSC_EN 0x400
> >> @@ -124,6 +127,17 @@ enum conversion_mode_sel {
> >> VF610_ADC_CONV_LOW_POWER,
> >> };
> >>
> >> +enum lst_adder_sel {
> >> + VF610_ADCK_CYCLES_3,
> >> + VF610_ADCK_CYCLES_5,
> >> + VF610_ADCK_CYCLES_7,
> >> + VF610_ADCK_CYCLES_9,
> >> + VF610_ADCK_CYCLES_13,
> >> + VF610_ADCK_CYCLES_17,
> >> + VF610_ADCK_CYCLES_21,
> >> + VF610_ADCK_CYCLES_25,
> >> +};
> >> +
> >> struct vf610_adc_feature {
> >> enum clk_sel clk_sel;
> >> enum vol_ref vol_ref;
> >> @@ -132,6 +146,8 @@ struct vf610_adc_feature {
> >> int clk_div;
> >> int sample_rate;
> >> int res_mode;
> >> + u32 lst_adder_index;
> >> + u32 default_sample_time;
> >>
> >> bool calibration;
> >> bool ovwren;
> >> @@ -155,11 +171,13 @@ struct vf610_adc {
> >> };
> >>
> >> static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
> >> +static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 };
> >>
> >> static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
> >> {
> >> struct vf610_adc_feature *adc_feature = &info->adc_feature;
> >> unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
> >> + u32 adck_period, lst_addr_min;
> >> int divisor, i;
> >>
> >> adck_rate = info->max_adck_rate[adc_feature->conv_mode];
> >> @@ -174,6 +192,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
> >> }
> >>
> >> /*
> >> + * Determine the long sample time adder value to be used based
> >> + * on the default minimum sample time provided.
> >> + */
> >> + adck_period = NSEC_PER_SEC / adck_rate;
> >> + lst_addr_min = adc_feature->default_sample_time / adck_period;
> >> + for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) {
> >> + if (vf610_lst_adder[i] > lst_addr_min) {
> >> + adc_feature->lst_adder_index = i;
> >> + break;
> >> + }
> >> + }
> >> +
> >> + /*
> >> * Calculate ADC sample frequencies
> >> * Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
> >> * which is the same as bus clock.
> >> @@ -182,12 +213,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
> >> * SFCAdder: fixed to 6 ADCK cycles
> >> * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
> >> * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
> >> - * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
> >> + * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles
> >> */
> >> adck_rate = ipg_rate / info->adc_feature.clk_div;
> >> for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
> >> info->sample_freq_avail[i] =
> >> - adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
> >> + adck_rate / (6 + vf610_hw_avgs[i] *
> >> + (25 + vf610_lst_adder[adc_feature->lst_adder_index]));
> >> }
> >>
> >> static inline void vf610_adc_cfg_init(struct vf610_adc *info)
> >> @@ -347,8 +379,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info)
> >> break;
> >> }
> >>
> >> - /* Use the short sample mode */
> >> - cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
> >> + /*
> >> + * Set ADLSMP and ADSTS based on the Long Sample Time Adder value
> >> + * determined.
> >> + */
> >> + switch (adc_feature->lst_adder_index) {
> >> + case VF610_ADCK_CYCLES_3:
> >> + break;
> >> + case VF610_ADCK_CYCLES_5:
> >> + cfg_data |= VF610_ADC_ADSTS_SHORT;
> >> + break;
> >> + case VF610_ADCK_CYCLES_7:
> >> + cfg_data |= VF610_ADC_ADSTS_NORMAL;
> >> + break;
> >> + case VF610_ADCK_CYCLES_9:
> >> + cfg_data |= VF610_ADC_ADSTS_LONG;
> >> + break;
> >> + case VF610_ADCK_CYCLES_13:
> >> + cfg_data |= VF610_ADC_ADLSMP_LONG;
> >> + break;
> >> + case VF610_ADCK_CYCLES_17:
> >> + cfg_data |= VF610_ADC_ADLSMP_LONG;
> >> + cfg_data |= VF610_ADC_ADSTS_SHORT;
> >> + break;
> >> + case VF610_ADCK_CYCLES_21:
> >> + cfg_data |= VF610_ADC_ADLSMP_LONG;
> >> + cfg_data |= VF610_ADC_ADSTS_NORMAL;
> >> + break;
> >> + case VF610_ADCK_CYCLES_25:
> >> + cfg_data |= VF610_ADC_ADLSMP_LONG;
> >> + cfg_data |= VF610_ADC_ADSTS_NORMAL;
> >> + break;
> >> + default:
> >> + dev_err(info->dev, "error in sample time select\n");
> >> + }
> >>
> >> /* update hardware average selection */
> >> cfg_data &= ~VF610_ADC_AVGS_MASK;
> >> @@ -712,6 +776,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
> >>
> >> of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency",
> >> info->max_adck_rate, 3);
> >> + of_property_read_u32(pdev->dev.of_node, "fsl,min-sample-time",
> >> + &info->adc_feature.default_sample_time);
> >>
> >> platform_set_drvdata(pdev, indio_dev);
> >>
> >> --
> >> 2.4.2
> >>
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> > the body of a message to [email protected]
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
>