Discussion:
[linux-sunxi] [PATCH 01/16] dt-bindings: update the Allwinner GPADC device tree binding for H3 & A83T
Philipp Rossak
2018-01-26 15:19:26 UTC
Permalink
Allwinner H3 features a thermal sensor like the one in A33, but has its
register re-arranged, the clock divider moved to CCU (originally the
clock divider is in ADC) and added a pair of bus clock and reset.

Allwinner A83T features a thermal sensor similar to the H3, the ths clock,
the bus clock and the reset was removed from the CCU. The THS in A83T
has a clock that is directly connected and runs with 24 MHz.

Update the binding document to cover H3 and A83T.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
.../devicetree/bindings/mfd/sun4i-gpadc.txt | 50 ++++++++++++++++++++--
1 file changed, 47 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/sun4i-gpadc.txt b/Documentation/devicetree/bindings/mfd/sun4i-gpadc.txt
index 86dd8191b04c..f6b939617a6d 100644
--- a/Documentation/devicetree/bindings/mfd/sun4i-gpadc.txt
+++ b/Documentation/devicetree/bindings/mfd/sun4i-gpadc.txt
@@ -4,12 +4,35 @@ The Allwinner SoCs all have an ADC that can also act as a thermal sensor
and sometimes as a touchscreen controller.

Required properties:
- - compatible: "allwinner,sun8i-a33-ths",
+ - compatible: must contain one of the following compatibles:
+ - "allwinner,sun8i-a33-ths"
+ - "allwinner,sun8i-h3-ths"
+ - "allwinner,sun8i-a83t-ths"
- reg: mmio address range of the chip,
- - #thermal-sensor-cells: shall be 0,
+ - #thermal-sensor-cells: shall be 0 or 1,
- #io-channel-cells: shall be 0,

-Example:
+Required properties for the following compatibles:
+ - "allwinner,sun8i-h3-ths"
+ - "allwinner,sun8i-a83t-ths"
+ - interrupts: the sampling interrupt of the ADC,
+
+Required properties for the following compatibles:
+ - "allwinner,sun8i-h3-ths"
+ - clocks: the bus clock and the input clock of the ADC,
+ - clock-names: should be "bus" and "mod",
+ - resets: the bus reset of the ADC,
+
+Optional properties for the following compatibles:
+ - "allwinner,sun8i-h3-ths"
+ - nvmem-cells: A phandle to the calibration data provided by a nvmem device.
+ If unspecified default values shall be used. The size should
+ be 0x4 or 0x8, depending on the amount of CDATA registers.
+ - nvmem-cell-names: Should be "calibration".
+
+Details see: bindings/nvmem/nvmem.txt
+
+Example for A33:
ths: ***@1c25000 {
compatible = "allwinner,sun8i-a33-ths";
reg = <0x01c25000 0x100>;
@@ -17,6 +40,27 @@ Example:
#io-channel-cells = <0>;
};

+Example for H3:
+ ths: thermal-***@1c25000 {
+ compatible = "allwinner,sun8i-h3-ths";
+ reg = <0x01c25000 0x400>;
+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
+ clock-names = "bus", "mod";
+ resets = <&ccu RST_BUS_THS>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ #thermal-sensor-cells = <0>;
+ #io-channel-cells = <0>;
+ };
+
+Example for A83T:
+ ths: thermal-***@1f04000 {
+ compatible = "allwinner,sun8i-a83t-ths";
+ reg = <0x01f04000 0x100>;
+ interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ #thermal-sensor-cells = <1>;
+ #io-channel-cells = <0>;
+ };
+
sun4i, sun5i and sun6i SoCs are also supported via the older binding:

sun4i resistive touchscreen controller
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:28 UTC
Permalink
From: Icenowy Zheng <***@aosc.io>

As the H3 SoC, which is also in sun8i line, has totally different
register map for the thermal sensor (a cut down version of GPADC), we
should rename A23/A33-specified registers to contain A33, in order to
prevent obfuscation with H3 registers. Currently these registers are
only prefixed "SUN8I", not "SUN8I_A33".

Add "_A33" after "SUN8I" on the register names.

Signed-off-by: Icenowy Zheng <***@aosc.io>
Reviewed-by: Chen-Yu Tsai <***@csie.org>
Acked-by: Maxime Ripard <***@free-electrons.com>
Acked-by: Lee Jones <***@linaro.org>
---
drivers/iio/adc/sun4i-gpadc-iio.c | 2 +-
include/linux/mfd/sun4i-gpadc.h | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 04d7147e0110..03804ff9c006 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -88,7 +88,7 @@ static const struct gpadc_data sun6i_gpadc_data = {
static const struct gpadc_data sun8i_a33_gpadc_data = {
.temp_offset = -1662,
.temp_scale = 162,
- .tp_mode_en = SUN8I_GPADC_CTRL1_CHOP_TEMP_EN,
+ .tp_mode_en = SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN,
};

struct sun4i_gpadc_iio {
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 139872c2e0fe..78d31984a222 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -38,9 +38,9 @@
#define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(3, 0) & BIT(x))
#define SUN6I_GPADC_CTRL1_ADC_CHAN_MASK GENMASK(3, 0)

-/* TP_CTRL1 bits for sun8i SoCs */
-#define SUN8I_GPADC_CTRL1_CHOP_TEMP_EN BIT(8)
-#define SUN8I_GPADC_CTRL1_GPADC_CALI_EN BIT(7)
+/* TP_CTRL1 bits for A33 */
+#define SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN BIT(8)
+#define SUN8I_A33_GPADC_CTRL1_GPADC_CALI_EN BIT(7)

#define SUN4I_GPADC_CTRL2 0x08
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:27 UTC
Permalink
This commit enables the SUN4I_GPADC config option and
sets the value to yes. This is needed to enable the ths sensors.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
arch/arm/configs/sunxi_defconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index 5caaf971fb50..52c3990b9d91 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -131,6 +131,7 @@ CONFIG_DMA_SUN6I=y
CONFIG_EXTCON=y
CONFIG_IIO=y
CONFIG_AXP20X_ADC=y
+CONFIG_SUN4I_GPADC=y
CONFIG_PWM=y
CONFIG_PWM_SUN4I=y
CONFIG_PHY_SUN4I_USB=y
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:29 UTC
Permalink
For adding newer sensor some basic rework of the code is necessary.

This commit reworks the code and allows the sampling start/end code and
the position of value readout register to be altered. Later the start/end
functions will be used to configure the ths and start/stop the
sampling.

Signed-off-by: Icenowy Zheng <***@aosc.io>
Signed-off-by: Philipp Rossak <***@gmail.com>
---
drivers/iio/adc/sun4i-gpadc-iio.c | 87 +++++++++++++++++++++++++++++++++++----
include/linux/mfd/sun4i-gpadc.h | 19 +++++++--
2 files changed, 94 insertions(+), 12 deletions(-)

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 03804ff9c006..363936b37c5a 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -49,6 +49,18 @@ static unsigned int sun6i_gpadc_chan_select(unsigned int chan)
return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
}

+struct sun4i_gpadc_iio;
+
+/*
+ * Prototypes for these functions, which enable these functions to be
+ * referenced in gpadc_data structures.
+ */
+static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info);
+static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info);
+
+static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info);
+static int sunxi_ths_sample_end(struct sun4i_gpadc_iio *info);
+
struct gpadc_data {
int temp_offset;
int temp_scale;
@@ -56,6 +68,13 @@ struct gpadc_data {
unsigned int tp_adc_select;
unsigned int (*adc_chan_select)(unsigned int chan);
unsigned int adc_chan_mask;
+ unsigned int temp_data;
+ int (*sample_start)(struct sun4i_gpadc_iio *info);
+ int (*sample_end)(struct sun4i_gpadc_iio *info);
+ u32 ctrl0_map;
+ u32 ctrl2_map;
+ u32 sensor_en_map;
+ u32 filter_map;
};

static const struct gpadc_data sun4i_gpadc_data = {
@@ -65,6 +84,9 @@ static const struct gpadc_data sun4i_gpadc_data = {
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};

static const struct gpadc_data sun5i_gpadc_data = {
@@ -74,6 +96,9 @@ static const struct gpadc_data sun5i_gpadc_data = {
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};

static const struct gpadc_data sun6i_gpadc_data = {
@@ -83,12 +108,18 @@ static const struct gpadc_data sun6i_gpadc_data = {
.tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun6i_gpadc_chan_select,
.adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};

static const struct gpadc_data sun8i_a33_gpadc_data = {
.temp_offset = -1662,
.temp_scale = 162,
.tp_mode_en = SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};

struct sun4i_gpadc_iio {
@@ -277,7 +308,7 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
if (info->no_irq) {
pm_runtime_get_sync(indio_dev->dev.parent);

- regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val);
+ regmap_read(info->regmap, info->data->temp_data, val);

pm_runtime_mark_last_busy(indio_dev->dev.parent);
pm_runtime_put_autosuspend(indio_dev->dev.parent);
@@ -382,10 +413,8 @@ static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}

-static int sun4i_gpadc_runtime_suspend(struct device *dev)
+static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)
{
- struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
-
/* Disable the ADC on IP */
regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0);
/* Disable temperature sensor on IP */
@@ -394,19 +423,32 @@ static int sun4i_gpadc_runtime_suspend(struct device *dev)
return 0;
}

-static int sun4i_gpadc_runtime_resume(struct device *dev)
+static int sunxi_ths_sample_end(struct sun4i_gpadc_iio *info)
+{
+ /* Disable temperature sensor */
+ regmap_write(info->regmap, SUNXI_THS_CTRL2, 0x0);
+
+ return 0;
+}
+
+static int sun4i_gpadc_runtime_suspend(struct device *dev)
{
struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));

+ return info->data->sample_end(info);
+}
+
+static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
+{
/* clkin = 6MHz */
regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) |
SUN4I_GPADC_CTRL0_FS_DIV(7) |
- SUN4I_GPADC_CTRL0_T_ACQ(63));
+ SUNXI_THS_ACQ0(63));
regmap_write(info->regmap, SUN4I_GPADC_CTRL1, info->data->tp_mode_en);
regmap_write(info->regmap, SUN4I_GPADC_CTRL3,
- SUN4I_GPADC_CTRL3_FILTER_EN |
- SUN4I_GPADC_CTRL3_FILTER_TYPE(1));
+ SUNXI_THS_FILTER_EN |
+ SUNXI_THS_FILTER_TYPE(1));
/* period = SUN4I_GPADC_TPR_TEMP_PERIOD * 256 * 16 / clkin; ~0.6s */
regmap_write(info->regmap, SUN4I_GPADC_TPR,
SUN4I_GPADC_TPR_TEMP_ENABLE |
@@ -415,6 +457,35 @@ static int sun4i_gpadc_runtime_resume(struct device *dev)
return 0;
}

+static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info)
+{
+ u32 value;
+
+ if (info->data->ctrl0_map)
+ regmap_write(info->regmap, SUNXI_THS_CTRL0,
+ info->data->ctrl0_map);
+
+ regmap_write(info->regmap, SUNXI_THS_CTRL2,
+ info->data->ctrl2_map);
+
+ regmap_write(info->regmap, SUNXI_THS_FILTER,
+ info->data->filter_map);
+
+ regmap_read(info->regmap, SUNXI_THS_CTRL2, &value);
+
+ regmap_write(info->regmap, SUNXI_THS_CTRL2,
+ info->data->sensor_en_map | value);
+
+ return 0;
+}
+
+static int sun4i_gpadc_runtime_resume(struct device *dev)
+{
+ struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+
+ return info->data->sample_start(info);
+}
+
static int sun4i_gpadc_get_temp(void *data, int *temp)
{
struct sun4i_gpadc_iio *info = data;
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 78d31984a222..39e096c3ddac 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -17,7 +17,6 @@
#define SUN4I_GPADC_CTRL0_ADC_CLK_SELECT BIT(22)
#define SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(x) ((GENMASK(1, 0) & (x)) << 20)
#define SUN4I_GPADC_CTRL0_FS_DIV(x) ((GENMASK(3, 0) & (x)) << 16)
-#define SUN4I_GPADC_CTRL0_T_ACQ(x) (GENMASK(15, 0) & (x))

#define SUN4I_GPADC_CTRL1 0x04

@@ -51,9 +50,6 @@

#define SUN4I_GPADC_CTRL3 0x0c

-#define SUN4I_GPADC_CTRL3_FILTER_EN BIT(2)
-#define SUN4I_GPADC_CTRL3_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
-
#define SUN4I_GPADC_TPR 0x18

#define SUN4I_GPADC_TPR_TEMP_ENABLE BIT(16)
@@ -90,6 +86,21 @@
/* 10s delay before suspending the IP */
#define SUN4I_GPADC_AUTOSUSPEND_DELAY 10000

+/* SUNXI_THS COMMON REGISTERS + DEFINES */
+#define SUNXI_THS_CTRL0 0x00
+#define SUNXI_THS_CTRL2 0x40
+#define SUNXI_THS_FILTER 0x70
+
+#define SUNXI_THS_FILTER_EN BIT(2)
+#define SUNXI_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
+#define SUNXI_THS_ACQ0(x) (GENMASK(15, 0) & (x))
+#define SUNXI_THS_ACQ1(x) (GENMASK(31, 16) & ((x) << 16))
+
+#define SUNXI_THS_TEMP_SENSE_EN0 BIT(0)
+#define SUNXI_THS_TEMP_SENSE_EN1 BIT(1)
+#define SUNXI_THS_TEMP_SENSE_EN2 BIT(2)
+#define SUNXI_THS_TEMP_SENSE_EN3 BIT(3)
+
struct sun4i_gpadc_dev {
struct device *dev;
struct regmap *regmap;
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-28 13:34:17 UTC
Permalink
On Fri, 26 Jan 2018 16:19:29 +0100
Post by Philipp Rossak
For adding newer sensor some basic rework of the code is necessary.
This commit reworks the code and allows the sampling start/end code and
the position of value readout register to be altered. Later the start/end
functions will be used to configure the ths and start/stop the
sampling.
Hmm. It almost always turns out to be a bad idea to assume a particular
set of registers will be consistent across a hardware family. Usual convention
is just to prefix them with the first supported device and use them across
the variants where they are correct. I.e. don't use wild cards or generic
names as they often end up implying a wider range of applicability than
we want.
The new THS sensors seems to use the same THS ip core, only configured
with different amount of sensors. So for H3, A83T, H5, A80 and A64 the
registers are all the same.

I think the big question is, do we want to have a few very big patches.
Or more small patches with code that is used in later patches.
A few other comments inline. Reworking code to make it ready for later
patches is fine, but this also adds a lot of new code which isn't used until
much later in the series. Move it there...
please see comments below.
Post by Philipp Rossak
---
drivers/iio/adc/sun4i-gpadc-iio.c | 87 +++++++++++++++++++++++++++++++++++----
include/linux/mfd/sun4i-gpadc.h | 19 +++++++--
2 files changed, 94 insertions(+), 12 deletions(-)
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 03804ff9c006..363936b37c5a 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -49,6 +49,18 @@ static unsigned int sun6i_gpadc_chan_select(unsigned int chan)
return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
}
+struct sun4i_gpadc_iio;
+
+/*
+ * Prototypes for these functions, which enable these functions to be
+ * referenced in gpadc_data structures.
+ */
+static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info);
+static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info);
+
+static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info);
Superficially this appears to be introduced but not used... Patch 9
is first to use it I think? Introduce it then rather than here.
You are right, this function is used first in Patch 9. In an very early
version, I had this together with Patch 9. But then I had the feeling
that everything got too messy... Right now this is a very big patch
series and I wanted to have a clear structure in it and easy to review.

If I would rework this it will end up in squashing, Patch 4, Parts of
Patch 7, Patch 8 and Patch 9.
Post by Philipp Rossak
+static int sunxi_ths_sample_end(struct sun4i_gpadc_iio *info);
+
struct gpadc_data {
int temp_offset;
int temp_scale;
@@ -56,6 +68,13 @@ struct gpadc_data {
unsigned int tp_adc_select;
unsigned int (*adc_chan_select)(unsigned int chan);
unsigned int adc_chan_mask;
+ unsigned int temp_data;
+ int (*sample_start)(struct sun4i_gpadc_iio *info);
+ int (*sample_end)(struct sun4i_gpadc_iio *info);
+ u32 ctrl0_map;
+ u32 ctrl2_map;
+ u32 sensor_en_map;
+ u32 filter_map;
};
static const struct gpadc_data sun4i_gpadc_data = {
@@ -65,6 +84,9 @@ static const struct gpadc_data sun4i_gpadc_data = {
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};
static const struct gpadc_data sun5i_gpadc_data = {
@@ -74,6 +96,9 @@ static const struct gpadc_data sun5i_gpadc_data = {
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};
static const struct gpadc_data sun6i_gpadc_data = {
@@ -83,12 +108,18 @@ static const struct gpadc_data sun6i_gpadc_data = {
.tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun6i_gpadc_chan_select,
.adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};
static const struct gpadc_data sun8i_a33_gpadc_data = {
.temp_offset = -1662,
.temp_scale = 162,
.tp_mode_en = SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};
struct sun4i_gpadc_iio {
@@ -277,7 +308,7 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
if (info->no_irq) {
pm_runtime_get_sync(indio_dev->dev.parent);
- regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val);
+ regmap_read(info->regmap, info->data->temp_data, val);
pm_runtime_mark_last_busy(indio_dev->dev.parent);
pm_runtime_put_autosuspend(indio_dev->dev.parent);
@@ -382,10 +413,8 @@ static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int sun4i_gpadc_runtime_suspend(struct device *dev)
+static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)
{
- struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
-
/* Disable the ADC on IP */
regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0);
/* Disable temperature sensor on IP */
@@ -394,19 +423,32 @@ static int sun4i_gpadc_runtime_suspend(struct device *dev)
return 0;
}
-static int sun4i_gpadc_runtime_resume(struct device *dev)
+static int sunxi_ths_sample_end(struct sun4i_gpadc_iio *info)
+{
+ /* Disable temperature sensor */
+ regmap_write(info->regmap, SUNXI_THS_CTRL2, 0x0);
+
+ return 0;
+}
+
+static int sun4i_gpadc_runtime_suspend(struct device *dev)
{
struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+ return info->data->sample_end(info);
+}
+
+static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
+{
/* clkin = 6MHz */
regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) |
SUN4I_GPADC_CTRL0_FS_DIV(7) |
- SUN4I_GPADC_CTRL0_T_ACQ(63));
+ SUNXI_THS_ACQ0(63));
regmap_write(info->regmap, SUN4I_GPADC_CTRL1, info->data->tp_mode_en);
regmap_write(info->regmap, SUN4I_GPADC_CTRL3,
- SUN4I_GPADC_CTRL3_FILTER_EN |
- SUN4I_GPADC_CTRL3_FILTER_TYPE(1));
+ SUNXI_THS_FILTER_EN |
+ SUNXI_THS_FILTER_TYPE(1));
Why if these are temperature sensor features are we setting them in the
general purpose ADC start function?
This is part of the olds sensors (before Allwinner reworked their
temperature sensor (only ths) ). Those "old" sensors integrate an ADC
and a Thermal sensor in one ip block/register space. I don't want to
break those sensors/adc, since I'm not able to test them!
Post by Philipp Rossak
/* period = SUN4I_GPADC_TPR_TEMP_PERIOD * 256 * 16 / clkin; ~0.6s */
regmap_write(info->regmap, SUN4I_GPADC_TPR,
SUN4I_GPADC_TPR_TEMP_ENABLE |
@@ -415,6 +457,35 @@ static int sun4i_gpadc_runtime_resume(struct device *dev)
return 0;
}
+static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info)
+{
+ u32 value;
+
+ if (info->data->ctrl0_map)
+ regmap_write(info->regmap, SUNXI_THS_CTRL0,
+ info->data->ctrl0_map);
+
+ regmap_write(info->regmap, SUNXI_THS_CTRL2,
+ info->data->ctrl2_map);
+
+ regmap_write(info->regmap, SUNXI_THS_FILTER,
+ info->data->filter_map);
+
+ regmap_read(info->regmap, SUNXI_THS_CTRL2, &value);
+
+ regmap_write(info->regmap, SUNXI_THS_CTRL2,
+ info->data->sensor_en_map | value);
+
+ return 0;
+}
+
+static int sun4i_gpadc_runtime_resume(struct device *dev)
+{
+ struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+
+ return info->data->sample_start(info);
+}
+
static int sun4i_gpadc_get_temp(void *data, int *temp)
{
struct sun4i_gpadc_iio *info = data;
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 78d31984a222..39e096c3ddac 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -17,7 +17,6 @@
#define SUN4I_GPADC_CTRL0_ADC_CLK_SELECT BIT(22)
#define SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(x) ((GENMASK(1, 0) & (x)) << 20)
#define SUN4I_GPADC_CTRL0_FS_DIV(x) ((GENMASK(3, 0) & (x)) << 16)
-#define SUN4I_GPADC_CTRL0_T_ACQ(x) (GENMASK(15, 0) & (x))
#define SUN4I_GPADC_CTRL1 0x04
@@ -51,9 +50,6 @@
#define SUN4I_GPADC_CTRL3 0x0c
-#define SUN4I_GPADC_CTRL3_FILTER_EN BIT(2)
-#define SUN4I_GPADC_CTRL3_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
-
#define SUN4I_GPADC_TPR 0x18
#define SUN4I_GPADC_TPR_TEMP_ENABLE BIT(16)
@@ -90,6 +86,21 @@
/* 10s delay before suspending the IP */
#define SUN4I_GPADC_AUTOSUSPEND_DELAY 10000
+/* SUNXI_THS COMMON REGISTERS + DEFINES */
+#define SUNXI_THS_CTRL0 0x00
+#define SUNXI_THS_CTRL2 0x40
+#define SUNXI_THS_FILTER 0x70
+
+#define SUNXI_THS_FILTER_EN BIT(2)
+#define SUNXI_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
+#define SUNXI_THS_ACQ0(x) (GENMASK(15, 0) & (x))
+#define SUNXI_THS_ACQ1(x) (GENMASK(31, 16) & ((x) << 16))
+
+#define SUNXI_THS_TEMP_SENSE_EN0 BIT(0)
+#define SUNXI_THS_TEMP_SENSE_EN1 BIT(1)
+#define SUNXI_THS_TEMP_SENSE_EN2 BIT(2)
+#define SUNXI_THS_TEMP_SENSE_EN3 BIT(3)
+
struct sun4i_gpadc_dev {
struct device *dev;
struct regmap *regmap;
In general I'm ok with changing those things, but I would like to wait
for some more feedback/thoughts about this.

Thanks,
Philipp
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Icenowy Zheng
2018-01-28 13:37:59 UTC
Permalink
Post by Philipp Rossak
On Fri, 26 Jan 2018 16:19:29 +0100
Post by Philipp Rossak
For adding newer sensor some basic rework of the code is necessary.
This commit reworks the code and allows the sampling start/end code
and
Post by Philipp Rossak
the position of value readout register to be altered. Later the
start/end
Post by Philipp Rossak
functions will be used to configure the ths and start/stop the
sampling.
Hmm. It almost always turns out to be a bad idea to assume a
particular
set of registers will be consistent across a hardware family. Usual
convention
is just to prefix them with the first supported device and use them
across
the variants where they are correct. I.e. don't use wild cards or
generic
names as they often end up implying a wider range of applicability
than
we want.
The new THS sensors seems to use the same THS ip core, only configured
with different amount of sensors. So for H3, A83T, H5, A80 and A64 the
registers are all the same.
I think the big question is, do we want to have a few very big patches.
Or more small patches with code that is used in later patches.
Allwinner H6 has changed the THS core again.

Please consider this :-)
Post by Philipp Rossak
A few other comments inline. Reworking code to make it ready for
later
patches is fine, but this also adds a lot of new code which isn't
used until
much later in the series. Move it there...
please see comments below.
Post by Philipp Rossak
---
drivers/iio/adc/sun4i-gpadc-iio.c | 87
+++++++++++++++++++++++++++++++++++----
Post by Philipp Rossak
include/linux/mfd/sun4i-gpadc.h | 19 +++++++--
2 files changed, 94 insertions(+), 12 deletions(-)
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c
b/drivers/iio/adc/sun4i-gpadc-iio.c
Post by Philipp Rossak
index 03804ff9c006..363936b37c5a 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -49,6 +49,18 @@ static unsigned int
sun6i_gpadc_chan_select(unsigned int chan)
Post by Philipp Rossak
return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
}
+struct sun4i_gpadc_iio;
+
+/*
+ * Prototypes for these functions, which enable these functions to
be
Post by Philipp Rossak
+ * referenced in gpadc_data structures.
+ */
+static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info);
+static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info);
+
+static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info);
Superficially this appears to be introduced but not used... Patch 9
is first to use it I think? Introduce it then rather than here.
You are right, this function is used first in Patch 9. In an very early
version, I had this together with Patch 9. But then I had the feeling
that everything got too messy... Right now this is a very big patch
series and I wanted to have a clear structure in it and easy to review.
If I would rework this it will end up in squashing, Patch 4, Parts of
Patch 7, Patch 8 and Patch 9.
Post by Philipp Rossak
+static int sunxi_ths_sample_end(struct sun4i_gpadc_iio *info);
+
struct gpadc_data {
int temp_offset;
int temp_scale;
@@ -56,6 +68,13 @@ struct gpadc_data {
unsigned int tp_adc_select;
unsigned int (*adc_chan_select)(unsigned int chan);
unsigned int adc_chan_mask;
+ unsigned int temp_data;
+ int (*sample_start)(struct sun4i_gpadc_iio *info);
+ int (*sample_end)(struct sun4i_gpadc_iio *info);
+ u32 ctrl0_map;
+ u32 ctrl2_map;
+ u32 sensor_en_map;
+ u32 filter_map;
};
static const struct gpadc_data sun4i_gpadc_data = {
@@ -65,6 +84,9 @@ static const struct gpadc_data sun4i_gpadc_data =
{
Post by Philipp Rossak
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};
static const struct gpadc_data sun5i_gpadc_data = {
@@ -74,6 +96,9 @@ static const struct gpadc_data sun5i_gpadc_data =
{
Post by Philipp Rossak
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};
static const struct gpadc_data sun6i_gpadc_data = {
@@ -83,12 +108,18 @@ static const struct gpadc_data sun6i_gpadc_data
= {
Post by Philipp Rossak
.tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun6i_gpadc_chan_select,
.adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};
static const struct gpadc_data sun8i_a33_gpadc_data = {
.temp_offset = -1662,
.temp_scale = 162,
.tp_mode_en = SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
};
struct sun4i_gpadc_iio {
@@ -277,7 +308,7 @@ static int sun4i_gpadc_temp_read(struct iio_dev
*indio_dev, int *val)
Post by Philipp Rossak
if (info->no_irq) {
pm_runtime_get_sync(indio_dev->dev.parent);
- regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val);
+ regmap_read(info->regmap, info->data->temp_data, val);
pm_runtime_mark_last_busy(indio_dev->dev.parent);
pm_runtime_put_autosuspend(indio_dev->dev.parent);
@@ -382,10 +413,8 @@ static irqreturn_t
sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
Post by Philipp Rossak
return IRQ_HANDLED;
}
-static int sun4i_gpadc_runtime_suspend(struct device *dev)
+static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)
{
- struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
-
/* Disable the ADC on IP */
regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0);
/* Disable temperature sensor on IP */
@@ -394,19 +423,32 @@ static int sun4i_gpadc_runtime_suspend(struct
device *dev)
Post by Philipp Rossak
return 0;
}
-static int sun4i_gpadc_runtime_resume(struct device *dev)
+static int sunxi_ths_sample_end(struct sun4i_gpadc_iio *info)
+{
+ /* Disable temperature sensor */
+ regmap_write(info->regmap, SUNXI_THS_CTRL2, 0x0);
+
+ return 0;
+}
+
+static int sun4i_gpadc_runtime_suspend(struct device *dev)
{
struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+ return info->data->sample_end(info);
+}
+
+static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
+{
/* clkin = 6MHz */
regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) |
SUN4I_GPADC_CTRL0_FS_DIV(7) |
- SUN4I_GPADC_CTRL0_T_ACQ(63));
+ SUNXI_THS_ACQ0(63));
regmap_write(info->regmap, SUN4I_GPADC_CTRL1,
info->data->tp_mode_en);
Post by Philipp Rossak
regmap_write(info->regmap, SUN4I_GPADC_CTRL3,
- SUN4I_GPADC_CTRL3_FILTER_EN |
- SUN4I_GPADC_CTRL3_FILTER_TYPE(1));
+ SUNXI_THS_FILTER_EN |
+ SUNXI_THS_FILTER_TYPE(1));
Why if these are temperature sensor features are we setting them in
the
general purpose ADC start function?
This is part of the olds sensors (before Allwinner reworked their
temperature sensor (only ths) ). Those "old" sensors integrate an ADC
and a Thermal sensor in one ip block/register space. I don't want to
break those sensors/adc, since I'm not able to test them!
Post by Philipp Rossak
/* period = SUN4I_GPADC_TPR_TEMP_PERIOD * 256 * 16 / clkin; ~0.6s
*/
Post by Philipp Rossak
regmap_write(info->regmap, SUN4I_GPADC_TPR,
SUN4I_GPADC_TPR_TEMP_ENABLE |
@@ -415,6 +457,35 @@ static int sun4i_gpadc_runtime_resume(struct
device *dev)
Post by Philipp Rossak
return 0;
}
+static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info)
+{
+ u32 value;
+
+ if (info->data->ctrl0_map)
+ regmap_write(info->regmap, SUNXI_THS_CTRL0,
+ info->data->ctrl0_map);
+
+ regmap_write(info->regmap, SUNXI_THS_CTRL2,
+ info->data->ctrl2_map);
+
+ regmap_write(info->regmap, SUNXI_THS_FILTER,
+ info->data->filter_map);
+
+ regmap_read(info->regmap, SUNXI_THS_CTRL2, &value);
+
+ regmap_write(info->regmap, SUNXI_THS_CTRL2,
+ info->data->sensor_en_map | value);
+
+ return 0;
+}
+
+static int sun4i_gpadc_runtime_resume(struct device *dev)
+{
+ struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+
+ return info->data->sample_start(info);
+}
+
static int sun4i_gpadc_get_temp(void *data, int *temp)
{
struct sun4i_gpadc_iio *info = data;
diff --git a/include/linux/mfd/sun4i-gpadc.h
b/include/linux/mfd/sun4i-gpadc.h
Post by Philipp Rossak
index 78d31984a222..39e096c3ddac 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -17,7 +17,6 @@
#define SUN4I_GPADC_CTRL0_ADC_CLK_SELECT BIT(22)
#define SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(x) ((GENMASK(1, 0) &
(x)) << 20)
Post by Philipp Rossak
#define SUN4I_GPADC_CTRL0_FS_DIV(x) ((GENMASK(3, 0) & (x)) <<
16)
Post by Philipp Rossak
-#define SUN4I_GPADC_CTRL0_T_ACQ(x) (GENMASK(15, 0) & (x))
#define SUN4I_GPADC_CTRL1 0x04
@@ -51,9 +50,6 @@
#define SUN4I_GPADC_CTRL3 0x0c
-#define SUN4I_GPADC_CTRL3_FILTER_EN BIT(2)
-#define SUN4I_GPADC_CTRL3_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
-
#define SUN4I_GPADC_TPR 0x18
#define SUN4I_GPADC_TPR_TEMP_ENABLE BIT(16)
@@ -90,6 +86,21 @@
/* 10s delay before suspending the IP */
#define SUN4I_GPADC_AUTOSUSPEND_DELAY 10000
+/* SUNXI_THS COMMON REGISTERS + DEFINES */
+#define SUNXI_THS_CTRL0 0x00
+#define SUNXI_THS_CTRL2 0x40
+#define SUNXI_THS_FILTER 0x70
+
+#define SUNXI_THS_FILTER_EN BIT(2)
+#define SUNXI_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
+#define SUNXI_THS_ACQ0(x) (GENMASK(15, 0) & (x))
+#define SUNXI_THS_ACQ1(x) (GENMASK(31, 16) & ((x) << 16))
+
+#define SUNXI_THS_TEMP_SENSE_EN0 BIT(0)
+#define SUNXI_THS_TEMP_SENSE_EN1 BIT(1)
+#define SUNXI_THS_TEMP_SENSE_EN2 BIT(2)
+#define SUNXI_THS_TEMP_SENSE_EN3 BIT(3)
+
struct sun4i_gpadc_dev {
struct device *dev;
struct regmap *regmap;
In general I'm ok with changing those things, but I would like to wait
for some more feedback/thoughts about this.
Thanks,
Philipp
_______________________________________________
linux-arm-kernel mailing list
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-28 14:32:13 UTC
Permalink
This post might be inappropriate. Click to display it.
Philipp Rossak
2018-01-26 15:19:30 UTC
Permalink
For adding newer sensor some basic rework of the code is necessary.

The SoCs after H3 has newer thermal sensor ADCs, which have two clock
inputs (bus clock and sampling clock) and a reset. The registers are
also re-arranged.

This commit reworks the code, adds the process of the clocks and
resets.

Signed-off-by: Philipp Rossak <***@gmail.com>
Signed-off-by: Icenowy Zheng <***@aosc.io>
---
drivers/iio/adc/sun4i-gpadc-iio.c | 80 +++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 363936b37c5a..1a80744bd472 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -22,6 +22,7 @@
* shutdown for not being used.
*/

+#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -31,6 +32,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/thermal.h>
#include <linux/delay.h>

@@ -75,6 +77,9 @@ struct gpadc_data {
u32 ctrl2_map;
u32 sensor_en_map;
u32 filter_map;
+ bool has_bus_clk;
+ bool has_bus_rst;
+ bool has_mod_clk;
};

static const struct gpadc_data sun4i_gpadc_data = {
@@ -134,6 +139,9 @@ struct sun4i_gpadc_iio {
atomic_t ignore_temp_data_irq;
const struct gpadc_data *data;
bool no_irq;
+ struct clk *bus_clk;
+ struct clk *mod_clk;
+ struct reset_control *reset;
/* prevents concurrent reads of temperature and ADC */
struct mutex mutex;
struct thermal_zone_device *tzd;
@@ -435,6 +443,12 @@ static int sun4i_gpadc_runtime_suspend(struct device *dev)
{
struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));

+ if (info->data->has_mod_clk)
+ clk_disable(info->mod_clk);
+
+ if (info->data->has_bus_clk)
+ clk_disable(info->bus_clk);
+
return info->data->sample_end(info);
}

@@ -483,6 +497,12 @@ static int sun4i_gpadc_runtime_resume(struct device *dev)
{
struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));

+ if (info->data->has_mod_clk)
+ clk_enable(info->mod_clk);
+
+ if (info->data->has_bus_clk)
+ clk_enable(info->bus_clk);
+
return info->data->sample_start(info);
}

@@ -597,10 +617,61 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
return ret;
}

+ if (info->data->has_bus_rst) {
+ info->reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(info->reset)) {
+ ret = PTR_ERR(info->reset);
+ return ret;
+ }
+
+ ret = reset_control_deassert(info->reset);
+ if (ret)
+ return ret;
+ }
+
+ if (info->data->has_bus_clk) {
+ info->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(info->bus_clk)) {
+ ret = PTR_ERR(info->bus_clk);
+ goto assert_reset;
+ }
+
+ ret = clk_prepare_enable(info->bus_clk);
+ if (ret)
+ goto assert_reset;
+ }
+
+ if (info->data->has_mod_clk) {
+ info->mod_clk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(info->mod_clk)) {
+ ret = PTR_ERR(info->mod_clk);
+ goto disable_bus_clk;
+ }
+
+ /* Running at 6MHz */
+ ret = clk_set_rate(info->mod_clk, 4000000);
+ if (ret)
+ goto disable_bus_clk;
+
+ ret = clk_prepare_enable(info->mod_clk);
+ if (ret)
+ goto disable_bus_clk;
+ }
+
if (IS_ENABLED(CONFIG_THERMAL_OF))
info->sensor_device = &pdev->dev;

return 0;
+
+disable_bus_clk:
+ if (info->data->has_bus_clk)
+ clk_disable_unprepare(info->bus_clk);
+
+assert_reset:
+ if (info->data->has_bus_rst)
+ reset_control_assert(info->reset);
+
+ return ret;
}

static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
@@ -766,6 +837,15 @@ static int sun4i_gpadc_remove(struct platform_device *pdev)
if (!info->no_irq)
iio_map_array_unregister(indio_dev);

+ if (info->data->has_mod_clk)
+ clk_disable_unprepare(info->mod_clk);
+
+ if (info->data->has_bus_clk)
+ clk_disable_unprepare(info->bus_clk);
+
+ if (info->data->has_bus_rst)
+ reset_control_assert(info->reset);
+
return 0;
}
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-28 11:34:14 UTC
Permalink
On Fri, 26 Jan 2018 16:19:30 +0100
Post by Philipp Rossak
For adding newer sensor some basic rework of the code is necessary.
The SoCs after H3 has newer thermal sensor ADCs, which have two clock
inputs (bus clock and sampling clock) and a reset. The registers are
also re-arranged.
This commit reworks the code, adds the process of the clocks and
resets.
Both clock and reset code is safe against null parameters, so you can
drop a lot of 'is it here' checks in this. They could be argued to
act as documentation of the fact we really don't expect them in some cases
I suppose...
Ok, this sounds good for me!
I will fix that in the next version of this patch series.
Post by Philipp Rossak
---
drivers/iio/adc/sun4i-gpadc-iio.c | 80 +++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 363936b37c5a..1a80744bd472 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -22,6 +22,7 @@
* shutdown for not being used.
*/
+#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -31,6 +32,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/thermal.h>
#include <linux/delay.h>
@@ -75,6 +77,9 @@ struct gpadc_data {
u32 ctrl2_map;
u32 sensor_en_map;
u32 filter_map;
+ bool has_bus_clk;
+ bool has_bus_rst;
+ bool has_mod_clk;
};
static const struct gpadc_data sun4i_gpadc_data = {
@@ -134,6 +139,9 @@ struct sun4i_gpadc_iio {
atomic_t ignore_temp_data_irq;
const struct gpadc_data *data;
bool no_irq;
+ struct clk *bus_clk;
+ struct clk *mod_clk;
+ struct reset_control *reset;
/* prevents concurrent reads of temperature and ADC */
struct mutex mutex;
struct thermal_zone_device *tzd;
@@ -435,6 +443,12 @@ static int sun4i_gpadc_runtime_suspend(struct device *dev)
{
struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+ if (info->data->has_mod_clk)
+ clk_disable(info->mod_clk);
Safe against null parameter... (see below)
Post by Philipp Rossak
+
+ if (info->data->has_bus_clk)
+ clk_disable(info->bus_clk);
+
return info->data->sample_end(info);
}
@@ -483,6 +497,12 @@ static int sun4i_gpadc_runtime_resume(struct device *dev)
{
struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+ if (info->data->has_mod_clk)
+ clk_enable(info->mod_clk);
clk_enable is safe against null parameter so could do without the checks.
Post by Philipp Rossak
+
+ if (info->data->has_bus_clk)
+ clk_enable(info->bus_clk);
+
return info->data->sample_start(info);
}
@@ -597,10 +617,61 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
return ret;
}
+ if (info->data->has_bus_rst) {
+ info->reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(info->reset)) {
+ ret = PTR_ERR(info->reset);
+ return ret;
+ }
+
+ ret = reset_control_deassert(info->reset);
+ if (ret)
+ return ret;
+ }
+
+ if (info->data->has_bus_clk) {
+ info->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(info->bus_clk)) {
+ ret = PTR_ERR(info->bus_clk);
+ goto assert_reset;
+ }
+
+ ret = clk_prepare_enable(info->bus_clk);
+ if (ret)
+ goto assert_reset;
+ }
+
+ if (info->data->has_mod_clk) {
+ info->mod_clk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(info->mod_clk)) {
+ ret = PTR_ERR(info->mod_clk);
+ goto disable_bus_clk;
+ }
+
+ /* Running at 6MHz */
+ ret = clk_set_rate(info->mod_clk, 4000000);
+ if (ret)
+ goto disable_bus_clk;
+
+ ret = clk_prepare_enable(info->mod_clk);
+ if (ret)
+ goto disable_bus_clk;
+ }
+
if (IS_ENABLED(CONFIG_THERMAL_OF))
info->sensor_device = &pdev->dev;
return 0;
+
+ if (info->data->has_bus_clk)
+ clk_disable_unprepare(info->bus_clk);
+
+ if (info->data->has_bus_rst)
+ reset_control_assert(info->reset);
+
+ return ret;
}
static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
@@ -766,6 +837,15 @@ static int sun4i_gpadc_remove(struct platform_device *pdev)
if (!info->no_irq)
iio_map_array_unregister(indio_dev);
+ if (info->data->has_mod_clk)
+ clk_disable_unprepare(info->mod_clk);
clk_disable_unprepare is safe against a null parameter
so I don't think the checks are needed.
Post by Philipp Rossak
+
+ if (info->data->has_bus_clk)
+ clk_disable_unprepare(info->bus_clk);
+
+ if (info->data->has_bus_rst)
+ reset_control_assert(info->reset);
Safe against null parameter...
Post by Philipp Rossak
+
return 0;
}
Thanks,
Philipp
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:31 UTC
Permalink
For adding newer sensor some basic rework of the code is necessary.

This patch reworks the driver to be able to handle more than one
thermal sensor. Newer SoC like the A80 have 4 thermal sensors.
Because of this the maximal sensor count value was set to 4.

The sensor_id value is set during sensor registration and is for each
registered sensor indiviual. This makes it able to differntiate the
sensors when the value is read from the register.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
drivers/iio/adc/sun4i-gpadc-iio.c | 36 +++++++++++++++++++++++-------------
include/linux/mfd/sun4i-gpadc.h | 6 ++++++
2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 1a80744bd472..bff06f2798e8 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -70,7 +70,7 @@ struct gpadc_data {
unsigned int tp_adc_select;
unsigned int (*adc_chan_select)(unsigned int chan);
unsigned int adc_chan_mask;
- unsigned int temp_data;
+ unsigned int temp_data[MAX_SENSOR_COUNT];
int (*sample_start)(struct sun4i_gpadc_iio *info);
int (*sample_end)(struct sun4i_gpadc_iio *info);
u32 ctrl0_map;
@@ -80,6 +80,7 @@ struct gpadc_data {
bool has_bus_clk;
bool has_bus_rst;
bool has_mod_clk;
+ int sensor_count;
};

static const struct gpadc_data sun4i_gpadc_data = {
@@ -89,9 +90,10 @@ static const struct gpadc_data sun4i_gpadc_data = {
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
- .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
+ .sensor_count = 1,
};

static const struct gpadc_data sun5i_gpadc_data = {
@@ -101,9 +103,10 @@ static const struct gpadc_data sun5i_gpadc_data = {
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
- .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
+ .sensor_count = 1,
};

static const struct gpadc_data sun6i_gpadc_data = {
@@ -113,18 +116,20 @@ static const struct gpadc_data sun6i_gpadc_data = {
.tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun6i_gpadc_chan_select,
.adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
- .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
+ .sensor_count = 1,
};

static const struct gpadc_data sun8i_a33_gpadc_data = {
.temp_offset = -1662,
.temp_scale = 162,
.tp_mode_en = SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN,
- .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
+ .sensor_count = 1,
};

struct sun4i_gpadc_iio {
@@ -142,6 +147,7 @@ struct sun4i_gpadc_iio {
struct clk *bus_clk;
struct clk *mod_clk;
struct reset_control *reset;
+ int sensor_id;
/* prevents concurrent reads of temperature and ADC */
struct mutex mutex;
struct thermal_zone_device *tzd;
@@ -309,14 +315,15 @@ static int sun4i_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
return sun4i_gpadc_read(indio_dev, channel, val, info->fifo_data_irq);
}

-static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
+static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
+ int sensor)
{
struct sun4i_gpadc_iio *info = iio_priv(indio_dev);

if (info->no_irq) {
pm_runtime_get_sync(indio_dev->dev.parent);

- regmap_read(info->regmap, info->data->temp_data, val);
+ regmap_read(info->regmap, info->data->temp_data[sensor], val);

pm_runtime_mark_last_busy(indio_dev->dev.parent);
pm_runtime_put_autosuspend(indio_dev->dev.parent);
@@ -363,7 +370,7 @@ static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
ret = sun4i_gpadc_adc_read(indio_dev, chan->channel,
val);
else
- ret = sun4i_gpadc_temp_read(indio_dev, val);
+ ret = sun4i_gpadc_temp_read(indio_dev, val, 0);

if (ret)
return ret;
@@ -511,7 +518,7 @@ static int sun4i_gpadc_get_temp(void *data, int *temp)
struct sun4i_gpadc_iio *info = data;
int val, scale, offset;

- if (sun4i_gpadc_temp_read(info->indio_dev, &val))
+ if (sun4i_gpadc_temp_read(info->indio_dev, &val, info->sensor_id))
return -ETIMEDOUT;

sun4i_gpadc_temp_scale(info->indio_dev, &scale);
@@ -755,7 +762,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
{
struct sun4i_gpadc_iio *info;
struct iio_dev *indio_dev;
- int ret;
+ int ret, i;

indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
if (!indio_dev)
@@ -788,9 +795,12 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);

if (IS_ENABLED(CONFIG_THERMAL_OF)) {
- info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
- 0, info,
- &sun4i_ts_tz_ops);
+ for (i = 0; i < info->data->sensor_count; i++) {
+ info->sensor_id = i;
+ info->tzd = thermal_zone_of_sensor_register(
+ info->sensor_device,
+ i, info, &sun4i_ts_tz_ops);
+ }
/*
* Do not fail driver probing when failing to register in
* thermal because no thermal DT node is found.
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 39e096c3ddac..40b4dd9d2405 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -90,6 +90,10 @@
#define SUNXI_THS_CTRL0 0x00
#define SUNXI_THS_CTRL2 0x40
#define SUNXI_THS_FILTER 0x70
+#define SUNXI_THS_TDATA0 0x80
+#define SUNXI_THS_TDATA1 0x84
+#define SUNXI_THS_TDATA2 0x88
+#define SUNXI_THS_TDATA3 0x8c

#define SUNXI_THS_FILTER_EN BIT(2)
#define SUNXI_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
@@ -101,6 +105,8 @@
#define SUNXI_THS_TEMP_SENSE_EN2 BIT(2)
#define SUNXI_THS_TEMP_SENSE_EN3 BIT(3)

+#define MAX_SENSOR_COUNT 4
+
struct sun4i_gpadc_dev {
struct device *dev;
struct regmap *regmap;
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-28 14:10:36 UTC
Permalink
On Fri, 26 Jan 2018 16:19:31 +0100
multible -> multiple
^^ Ok, I will fix that.
Post by Philipp Rossak
For adding newer sensor some basic rework of the code is necessary.
This patch reworks the driver to be able to handle more than one
thermal sensor. Newer SoC like the A80 have 4 thermal sensors.
Because of this the maximal sensor count value was set to 4.
The sensor_id value is set during sensor registration and is for each
registered sensor indiviual. This makes it able to differntiate the
sensors when the value is read from the register.
Question inline about why you aren't exposing the additional temperature
sensors as IIO channels?
Fine to not do so I suppose, but needs justifying.
^^ Ok, I will rework the commit mesage. Detailed explanation see below.
Jonathan
Post by Philipp Rossak
---
drivers/iio/adc/sun4i-gpadc-iio.c | 36 +++++++++++++++++++++++-------------
include/linux/mfd/sun4i-gpadc.h | 6 ++++++
2 files changed, 29 insertions(+), 13 deletions(-)
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 1a80744bd472..bff06f2798e8 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -70,7 +70,7 @@ struct gpadc_data {
unsigned int tp_adc_select;
unsigned int (*adc_chan_select)(unsigned int chan);
unsigned int adc_chan_mask;
- unsigned int temp_data;
+ unsigned int temp_data[MAX_SENSOR_COUNT];
int (*sample_start)(struct sun4i_gpadc_iio *info);
int (*sample_end)(struct sun4i_gpadc_iio *info);
u32 ctrl0_map;
@@ -80,6 +80,7 @@ struct gpadc_data {
bool has_bus_clk;
bool has_bus_rst;
bool has_mod_clk;
+ int sensor_count;
};
static const struct gpadc_data sun4i_gpadc_data = {
@@ -89,9 +90,10 @@ static const struct gpadc_data sun4i_gpadc_data = {
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
- .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
+ .sensor_count = 1,
};
static const struct gpadc_data sun5i_gpadc_data = {
@@ -101,9 +103,10 @@ static const struct gpadc_data sun5i_gpadc_data = {
.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun4i_gpadc_chan_select,
.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
- .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
+ .sensor_count = 1,
};
static const struct gpadc_data sun6i_gpadc_data = {
@@ -113,18 +116,20 @@ static const struct gpadc_data sun6i_gpadc_data = {
.tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
.adc_chan_select = &sun6i_gpadc_chan_select,
.adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
- .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
+ .sensor_count = 1,
};
static const struct gpadc_data sun8i_a33_gpadc_data = {
.temp_offset = -1662,
.temp_scale = 162,
.tp_mode_en = SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN,
- .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
[*] ^^
Post by Philipp Rossak
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
+ .sensor_count = 1,
};
struct sun4i_gpadc_iio {
@@ -142,6 +147,7 @@ struct sun4i_gpadc_iio {
struct clk *bus_clk;
struct clk *mod_clk;
struct reset_control *reset;
+ int sensor_id;
/* prevents concurrent reads of temperature and ADC */
struct mutex mutex;
struct thermal_zone_device *tzd;
@@ -309,14 +315,15 @@ static int sun4i_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
return sun4i_gpadc_read(indio_dev, channel, val, info->fifo_data_irq);
}
-static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
+static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
+ int sensor)
{
struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
if (info->no_irq) {
pm_runtime_get_sync(indio_dev->dev.parent);
- regmap_read(info->regmap, info->data->temp_data, val);
+ regmap_read(info->regmap, info->data->temp_data[sensor], val);
pm_runtime_mark_last_busy(indio_dev->dev.parent);
pm_runtime_put_autosuspend(indio_dev->dev.parent);
@@ -363,7 +370,7 @@ static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
ret = sun4i_gpadc_adc_read(indio_dev, chan->channel,
val);
else
- ret = sun4i_gpadc_temp_read(indio_dev, val);
+ ret = sun4i_gpadc_temp_read(indio_dev, val, 0);
Wouldn't it make more sense to pass the channel number in here?
Looking at it, seems you only expose the first temperature sensor
as an IIO channel? Perhaps fair enough, but please justify that
decision in the patch description.
The "old" thermal sensors only have one ths sensor. This function is
only used with the older sensors when the adc and the ths is used. The
channel number is not related to that. This here is related to the
temp_data. register selection above (marked with [*]).
Post by Philipp Rossak
if (ret)
return ret;
@@ -511,7 +518,7 @@ static int sun4i_gpadc_get_temp(void *data, int *temp)
struct sun4i_gpadc_iio *info = data;
int val, scale, offset;
- if (sun4i_gpadc_temp_read(info->indio_dev, &val))
+ if (sun4i_gpadc_temp_read(info->indio_dev, &val, info->sensor_id))
return -ETIMEDOUT;
sun4i_gpadc_temp_scale(info->indio_dev, &scale);
@@ -755,7 +762,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
{
struct sun4i_gpadc_iio *info;
struct iio_dev *indio_dev;
- int ret;
+ int ret, i;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
if (!indio_dev)
@@ -788,9 +795,12 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
if (IS_ENABLED(CONFIG_THERMAL_OF)) {
- info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
- 0, info,
- &sun4i_ts_tz_ops);
+ for (i = 0; i < info->data->sensor_count; i++) {
+ info->sensor_id = i;
+ info->tzd = thermal_zone_of_sensor_register(
+ info->sensor_device,
+ i, info, &sun4i_ts_tz_ops);
+ }
/*
* Do not fail driver probing when failing to register in
* thermal because no thermal DT node is found.
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 39e096c3ddac..40b4dd9d2405 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -90,6 +90,10 @@
#define SUNXI_THS_CTRL0 0x00
#define SUNXI_THS_CTRL2 0x40
#define SUNXI_THS_FILTER 0x70
+#define SUNXI_THS_TDATA0 0x80
+#define SUNXI_THS_TDATA1 0x84
+#define SUNXI_THS_TDATA2 0x88
+#define SUNXI_THS_TDATA3 0x8c
#define SUNXI_THS_FILTER_EN BIT(2)
#define SUNXI_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
@@ -101,6 +105,8 @@
#define SUNXI_THS_TEMP_SENSE_EN2 BIT(2)
#define SUNXI_THS_TEMP_SENSE_EN3 BIT(3)
+#define MAX_SENSOR_COUNT 4
+
struct sun4i_gpadc_dev {
struct device *dev;
struct regmap *regmap;
Thanks,
Philipp
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:32 UTC
Permalink
This patch reworks the driver to support nvmem calibration cells.
The driver checks if the nvmem calibration is supported and reads out
the nvmem. At the beginning of the startup process the calibration data
is written to the related registers.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
drivers/iio/adc/sun4i-gpadc-iio.c | 52 +++++++++++++++++++++++++++++++++++++++
include/linux/mfd/sun4i-gpadc.h | 2 ++
2 files changed, 54 insertions(+)

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index bff06f2798e8..7b12666cdd9e 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -81,6 +82,7 @@ struct gpadc_data {
bool has_bus_rst;
bool has_mod_clk;
int sensor_count;
+ bool supports_nvmem;
};

static const struct gpadc_data sun4i_gpadc_data = {
@@ -94,6 +96,7 @@ static const struct gpadc_data sun4i_gpadc_data = {
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};

static const struct gpadc_data sun5i_gpadc_data = {
@@ -107,6 +110,7 @@ static const struct gpadc_data sun5i_gpadc_data = {
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};

static const struct gpadc_data sun6i_gpadc_data = {
@@ -120,6 +124,7 @@ static const struct gpadc_data sun6i_gpadc_data = {
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};

static const struct gpadc_data sun8i_a33_gpadc_data = {
@@ -130,6 +135,7 @@ static const struct gpadc_data sun8i_a33_gpadc_data = {
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};

struct sun4i_gpadc_iio {
@@ -148,6 +154,8 @@ struct sun4i_gpadc_iio {
struct clk *mod_clk;
struct reset_control *reset;
int sensor_id;
+ u32 calibration_data[2];
+ bool has_calibration_data[2];
/* prevents concurrent reads of temperature and ADC */
struct mutex mutex;
struct thermal_zone_device *tzd;
@@ -459,6 +467,17 @@ static int sun4i_gpadc_runtime_suspend(struct device *dev)
return info->data->sample_end(info);
}

+static void sunxi_calibrate(struct sun4i_gpadc_iio *info)
+{
+ if (info->has_calibration_data[0])
+ regmap_write(info->regmap, SUNXI_THS_CDATA_0_1,
+ info->calibration_data[0]);
+
+ if (info->has_calibration_data[1])
+ regmap_write(info->regmap, SUNXI_THS_CDATA_2_3,
+ info->calibration_data[1]);
+}
+
static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
{
/* clkin = 6MHz */
@@ -481,6 +500,7 @@ static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info)
{
u32 value;
+ sunxi_calibrate(info);

if (info->data->ctrl0_map)
regmap_write(info->regmap, SUNXI_THS_CTRL0,
@@ -602,6 +622,9 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
struct resource *mem;
void __iomem *base;
int ret;
+ struct nvmem_cell *cell;
+ ssize_t cell_size;
+ u64 *cell_data;

info->data = of_device_get_match_data(&pdev->dev);
if (!info->data)
@@ -616,6 +639,35 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
if (IS_ERR(base))
return PTR_ERR(base);

+ info->has_calibration_data[0] = false;
+ info->has_calibration_data[1] = false;
+
+ if (!info->data->supports_nvmem)
+ goto no_nvmem;
+
+ cell = devm_nvmem_cell_get(&pdev->dev, "calibration");
+ if (IS_ERR(cell)) {
+ if (PTR_ERR(cell) == -EPROBE_DEFER)
+ return PTR_ERR(cell);
+ } else {
+ cell_data = (u64 *)nvmem_cell_read(cell, &cell_size);
+ devm_nvmem_cell_put(&pdev->dev, cell);
+ if (cell_size <= 4) {
+ info->has_calibration_data[0] = true;
+ info->calibration_data[0] = be32_to_cpu(cell_data[0] &
+ GENMASK(31, 0));
+ } else if (cell_size <= 8) {
+ info->has_calibration_data[0] = true;
+ info->calibration_data[0] = be32_to_cpu(cell_data[0] &
+ GENMASK(31, 0));
+ info->has_calibration_data[1] = true;
+ info->calibration_data[1] = be32_to_cpu(
+ (cell_data[0] >> 32) & GENMASK(31, 0));
+ }
+ }
+
+no_nvmem:
+
info->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&sun4i_gpadc_regmap_config);
if (IS_ERR(info->regmap)) {
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 40b4dd9d2405..c251002431bd 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -90,6 +90,8 @@
#define SUNXI_THS_CTRL0 0x00
#define SUNXI_THS_CTRL2 0x40
#define SUNXI_THS_FILTER 0x70
+#define SUNXI_THS_CDATA_0_1 0x74
+#define SUNXI_THS_CDATA_2_3 0x78
#define SUNXI_THS_TDATA0 0x80
#define SUNXI_THS_TDATA1 0x84
#define SUNXI_THS_TDATA2 0x88
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-28 13:46:18 UTC
Permalink
On Fri, 26 Jan 2018 16:19:32 +0100
Post by Philipp Rossak
This patch reworks the driver to support nvmem calibration cells.
The driver checks if the nvmem calibration is supported and reads out
the nvmem. At the beginning of the startup process the calibration data
is written to the related registers.
A few minor suggestions inline.
Jonathan
Post by Philipp Rossak
---
drivers/iio/adc/sun4i-gpadc-iio.c | 52 +++++++++++++++++++++++++++++++++++++++
include/linux/mfd/sun4i-gpadc.h | 2 ++
2 files changed, 54 insertions(+)
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index bff06f2798e8..7b12666cdd9e 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -81,6 +82,7 @@ struct gpadc_data {
bool has_bus_rst;
bool has_mod_clk;
int sensor_count;
+ bool supports_nvmem;
};
static const struct gpadc_data sun4i_gpadc_data = {
@@ -94,6 +96,7 @@ static const struct gpadc_data sun4i_gpadc_data = {
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
static const struct gpadc_data sun5i_gpadc_data = {
@@ -107,6 +110,7 @@ static const struct gpadc_data sun5i_gpadc_data = {
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
static const struct gpadc_data sun6i_gpadc_data = {
@@ -120,6 +124,7 @@ static const struct gpadc_data sun6i_gpadc_data = {
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
static const struct gpadc_data sun8i_a33_gpadc_data = {
@@ -130,6 +135,7 @@ static const struct gpadc_data sun8i_a33_gpadc_data = {
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
struct sun4i_gpadc_iio {
@@ -148,6 +154,8 @@ struct sun4i_gpadc_iio {
struct clk *mod_clk;
struct reset_control *reset;
int sensor_id;
+ u32 calibration_data[2];
+ bool has_calibration_data[2];
/* prevents concurrent reads of temperature and ADC */
struct mutex mutex;
struct thermal_zone_device *tzd;
@@ -459,6 +467,17 @@ static int sun4i_gpadc_runtime_suspend(struct device *dev)
return info->data->sample_end(info);
}
+static void sunxi_calibrate(struct sun4i_gpadc_iio *info)
+{
+ if (info->has_calibration_data[0])
+ regmap_write(info->regmap, SUNXI_THS_CDATA_0_1,
+ info->calibration_data[0]);
+
+ if (info->has_calibration_data[1])
+ regmap_write(info->regmap, SUNXI_THS_CDATA_2_3,
+ info->calibration_data[1]);
+}
+
static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
{
/* clkin = 6MHz */
@@ -481,6 +500,7 @@ static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info)
{
u32 value;
+ sunxi_calibrate(info);
if (info->data->ctrl0_map)
regmap_write(info->regmap, SUNXI_THS_CTRL0,
@@ -602,6 +622,9 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
struct resource *mem;
void __iomem *base;
int ret;
+ struct nvmem_cell *cell;
+ ssize_t cell_size;
+ u64 *cell_data;
info->data = of_device_get_match_data(&pdev->dev);
if (!info->data)
@@ -616,6 +639,35 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
if (IS_ERR(base))
return PTR_ERR(base);
+ info->has_calibration_data[0] = false;
+ info->has_calibration_data[1] = false;
+
+ if (!info->data->supports_nvmem)
+ goto no_nvmem;
+
+ cell = devm_nvmem_cell_get(&pdev->dev, "calibration");
+ if (IS_ERR(cell)) {
+ if (PTR_ERR(cell) == -EPROBE_DEFER)
+ return PTR_ERR(cell);
Use a goto here to no_nvmem.
Then you can drop the below else to make things more readable.
Post by Philipp Rossak
+ } else {
+ cell_data = (u64 *)nvmem_cell_read(cell, &cell_size);
+ devm_nvmem_cell_put(&pdev->dev, cell);
I'm really not keen on use of devm for things we are intending
to drop almost immediately. Just use the non managed versions
and clean up properly in the error paths (if there are any
where it is needed - which there aren't that I can see)
^^ Ok, I will rework that.
Post by Philipp Rossak
+ if (cell_size <= 4) {
Is it valid if it is anything other than 4?
For sensors with only one sensor would be also a 2 valid, for those with
2 sensors ==> 4, with 3 sensors ==> 6 and with and with 4 sensors ==> 8.

In hardware we have in total to 32bit registers for calibration, thus I
thought it would be a good idea to use always four bytes per register.
If two bytes are used, they should be the default value.

But I agree, this needs a rework.
Post by Philipp Rossak
+ info->has_calibration_data[0] = true;
+ info->calibration_data[0] = be32_to_cpu(cell_data[0] &
+ GENMASK(31, 0));
Masking isn't needed, If you want to be paranoid there is the lower_32_bits
function..
^^ Ok, I will rework that.
Post by Philipp Rossak
+ } else if (cell_size <= 8) {
+ info->has_calibration_data[0] = true;
+ info->calibration_data[0] = be32_to_cpu(cell_data[0] &
+ GENMASK(31, 0));
This first block is repeated. Easy enough to avoid I think...
^^ Ok, I will rework that.
Post by Philipp Rossak
+ info->has_calibration_data[1] = true;
+ info->calibration_data[1] = be32_to_cpu(
+ (cell_data[0] >> 32) & GENMASK(31, 0));
+ }
+ }
+
+
info->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&sun4i_gpadc_regmap_config);
if (IS_ERR(info->regmap)) {
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 40b4dd9d2405..c251002431bd 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -90,6 +90,8 @@
#define SUNXI_THS_CTRL0 0x00
#define SUNXI_THS_CTRL2 0x40
#define SUNXI_THS_FILTER 0x70
+#define SUNXI_THS_CDATA_0_1 0x74
+#define SUNXI_THS_CDATA_2_3 0x78
#define SUNXI_THS_TDATA0 0x80
#define SUNXI_THS_TDATA1 0x84
#define SUNXI_THS_TDATA2 0x88
Thanks,
Philipp
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Icenowy Zheng
2018-01-28 13:52:36 UTC
Permalink
Post by Philipp Rossak
On Fri, 26 Jan 2018 16:19:32 +0100
Post by Philipp Rossak
This patch reworks the driver to support nvmem calibration cells.
The driver checks if the nvmem calibration is supported and reads
out
Post by Philipp Rossak
the nvmem. At the beginning of the startup process the calibration
data
Post by Philipp Rossak
is written to the related registers.
A few minor suggestions inline.
Jonathan
Post by Philipp Rossak
---
drivers/iio/adc/sun4i-gpadc-iio.c | 52
+++++++++++++++++++++++++++++++++++++++
Post by Philipp Rossak
include/linux/mfd/sun4i-gpadc.h | 2 ++
2 files changed, 54 insertions(+)
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c
b/drivers/iio/adc/sun4i-gpadc-iio.c
Post by Philipp Rossak
index bff06f2798e8..7b12666cdd9e 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -81,6 +82,7 @@ struct gpadc_data {
bool has_bus_rst;
bool has_mod_clk;
int sensor_count;
+ bool supports_nvmem;
};
static const struct gpadc_data sun4i_gpadc_data = {
@@ -94,6 +96,7 @@ static const struct gpadc_data sun4i_gpadc_data =
{
Post by Philipp Rossak
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
static const struct gpadc_data sun5i_gpadc_data = {
@@ -107,6 +110,7 @@ static const struct gpadc_data sun5i_gpadc_data
= {
Post by Philipp Rossak
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
static const struct gpadc_data sun6i_gpadc_data = {
@@ -120,6 +124,7 @@ static const struct gpadc_data sun6i_gpadc_data
= {
Post by Philipp Rossak
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
static const struct gpadc_data sun8i_a33_gpadc_data = {
@@ -130,6 +135,7 @@ static const struct gpadc_data
sun8i_a33_gpadc_data = {
Post by Philipp Rossak
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
BTW A33 claims to support calibration data according to the manual.
Post by Philipp Rossak
Post by Philipp Rossak
};
struct sun4i_gpadc_iio {
@@ -148,6 +154,8 @@ struct sun4i_gpadc_iio {
struct clk *mod_clk;
struct reset_control *reset;
int sensor_id;
+ u32 calibration_data[2];
+ bool has_calibration_data[2];
/* prevents concurrent reads of temperature and ADC */
struct mutex mutex;
struct thermal_zone_device *tzd;
@@ -459,6 +467,17 @@ static int sun4i_gpadc_runtime_suspend(struct
device *dev)
Post by Philipp Rossak
return info->data->sample_end(info);
}
+static void sunxi_calibrate(struct sun4i_gpadc_iio *info)
+{
+ if (info->has_calibration_data[0])
+ regmap_write(info->regmap, SUNXI_THS_CDATA_0_1,
+ info->calibration_data[0]);
+
+ if (info->has_calibration_data[1])
+ regmap_write(info->regmap, SUNXI_THS_CDATA_2_3,
+ info->calibration_data[1]);
+}
+
static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
{
/* clkin = 6MHz */
@@ -481,6 +500,7 @@ static int sun4i_gpadc_sample_start(struct
sun4i_gpadc_iio *info)
Post by Philipp Rossak
static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info)
{
u32 value;
+ sunxi_calibrate(info);
if (info->data->ctrl0_map)
regmap_write(info->regmap, SUNXI_THS_CTRL0,
@@ -602,6 +622,9 @@ static int sun4i_gpadc_probe_dt(struct
platform_device *pdev,
Post by Philipp Rossak
struct resource *mem;
void __iomem *base;
int ret;
+ struct nvmem_cell *cell;
+ ssize_t cell_size;
+ u64 *cell_data;
info->data = of_device_get_match_data(&pdev->dev);
if (!info->data)
@@ -616,6 +639,35 @@ static int sun4i_gpadc_probe_dt(struct
platform_device *pdev,
Post by Philipp Rossak
if (IS_ERR(base))
return PTR_ERR(base);
+ info->has_calibration_data[0] = false;
+ info->has_calibration_data[1] = false;
+
+ if (!info->data->supports_nvmem)
+ goto no_nvmem;
+
+ cell = devm_nvmem_cell_get(&pdev->dev, "calibration");
+ if (IS_ERR(cell)) {
+ if (PTR_ERR(cell) == -EPROBE_DEFER)
+ return PTR_ERR(cell);
Use a goto here to no_nvmem.
Then you can drop the below else to make things more readable.
Post by Philipp Rossak
+ } else {
+ cell_data = (u64 *)nvmem_cell_read(cell, &cell_size);
+ devm_nvmem_cell_put(&pdev->dev, cell);
I'm really not keen on use of devm for things we are intending
to drop almost immediately. Just use the non managed versions
and clean up properly in the error paths (if there are any
where it is needed - which there aren't that I can see)
^^ Ok, I will rework that.
Post by Philipp Rossak
+ if (cell_size <= 4) {
Is it valid if it is anything other than 4?
For sensors with only one sensor would be also a 2 valid, for those with
2 sensors ==> 4, with 3 sensors ==> 6 and with and with 4 sensors ==> 8.
In hardware we have in total to 32bit registers for calibration, thus I
thought it would be a good idea to use always four bytes per register.
If two bytes are used, they should be the default value.
But I agree, this needs a rework.
Post by Philipp Rossak
+ info->has_calibration_data[0] = true;
+ info->calibration_data[0] = be32_to_cpu(cell_data[0] &
+ GENMASK(31, 0));
Masking isn't needed, If you want to be paranoid there is the
lower_32_bits
function..
^^ Ok, I will rework that.
Post by Philipp Rossak
+ } else if (cell_size <= 8) {
+ info->has_calibration_data[0] = true;
+ info->calibration_data[0] = be32_to_cpu(cell_data[0] &
+ GENMASK(31, 0));
This first block is repeated. Easy enough to avoid I think...
^^ Ok, I will rework that.
Post by Philipp Rossak
+ info->has_calibration_data[1] = true;
+ info->calibration_data[1] = be32_to_cpu(
+ (cell_data[0] >> 32) & GENMASK(31, 0));
+ }
+ }
+
+
info->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&sun4i_gpadc_regmap_config);
if (IS_ERR(info->regmap)) {
diff --git a/include/linux/mfd/sun4i-gpadc.h
b/include/linux/mfd/sun4i-gpadc.h
Post by Philipp Rossak
index 40b4dd9d2405..c251002431bd 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -90,6 +90,8 @@
#define SUNXI_THS_CTRL0 0x00
#define SUNXI_THS_CTRL2 0x40
#define SUNXI_THS_FILTER 0x70
+#define SUNXI_THS_CDATA_0_1 0x74
+#define SUNXI_THS_CDATA_2_3 0x78
#define SUNXI_THS_TDATA0 0x80
#define SUNXI_THS_TDATA1 0x84
#define SUNXI_THS_TDATA2 0x88
Thanks,
Philipp
_______________________________________________
linux-arm-kernel mailing list
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-28 14:39:15 UTC
Permalink
Post by Icenowy Zheng
Post by Philipp Rossak
On Fri, 26 Jan 2018 16:19:32 +0100
Post by Philipp Rossak
This patch reworks the driver to support nvmem calibration cells.
The driver checks if the nvmem calibration is supported and reads
out
Post by Philipp Rossak
the nvmem. At the beginning of the startup process the calibration
data
Post by Philipp Rossak
is written to the related registers.
A few minor suggestions inline.
Jonathan
Post by Philipp Rossak
---
drivers/iio/adc/sun4i-gpadc-iio.c | 52
+++++++++++++++++++++++++++++++++++++++
Post by Philipp Rossak
include/linux/mfd/sun4i-gpadc.h | 2 ++
2 files changed, 54 insertions(+)
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c
b/drivers/iio/adc/sun4i-gpadc-iio.c
Post by Philipp Rossak
index bff06f2798e8..7b12666cdd9e 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -81,6 +82,7 @@ struct gpadc_data {
bool has_bus_rst;
bool has_mod_clk;
int sensor_count;
+ bool supports_nvmem;
};
static const struct gpadc_data sun4i_gpadc_data = {
@@ -94,6 +96,7 @@ static const struct gpadc_data sun4i_gpadc_data =
{
Post by Philipp Rossak
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
static const struct gpadc_data sun5i_gpadc_data = {
@@ -107,6 +110,7 @@ static const struct gpadc_data sun5i_gpadc_data
= {
Post by Philipp Rossak
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
static const struct gpadc_data sun6i_gpadc_data = {
@@ -120,6 +124,7 @@ static const struct gpadc_data sun6i_gpadc_data
= {
Post by Philipp Rossak
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
};
static const struct gpadc_data sun8i_a33_gpadc_data = {
@@ -130,6 +135,7 @@ static const struct gpadc_data
sun8i_a33_gpadc_data = {
Post by Philipp Rossak
.sample_start = sun4i_gpadc_sample_start,
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
+ .supports_nvmem = false,
BTW A33 claims to support calibration data according to the manual.
Yes that's true, but I haven't seen a sid/nvmem driver for the a33. If
that is available, we can change this for true (same on a83t).
Post by Icenowy Zheng
Post by Philipp Rossak
Post by Philipp Rossak
};
struct sun4i_gpadc_iio {
@@ -148,6 +154,8 @@ struct sun4i_gpadc_iio {
struct clk *mod_clk;
struct reset_control *reset;
int sensor_id;
+ u32 calibration_data[2];
+ bool has_calibration_data[2];
/* prevents concurrent reads of temperature and ADC */
struct mutex mutex;
struct thermal_zone_device *tzd;
@@ -459,6 +467,17 @@ static int sun4i_gpadc_runtime_suspend(struct
device *dev)
Post by Philipp Rossak
return info->data->sample_end(info);
}
+static void sunxi_calibrate(struct sun4i_gpadc_iio *info)
+{
+ if (info->has_calibration_data[0])
+ regmap_write(info->regmap, SUNXI_THS_CDATA_0_1,
+ info->calibration_data[0]);
+
+ if (info->has_calibration_data[1])
+ regmap_write(info->regmap, SUNXI_THS_CDATA_2_3,
+ info->calibration_data[1]);
+}
+
static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
{
/* clkin = 6MHz */
@@ -481,6 +500,7 @@ static int sun4i_gpadc_sample_start(struct
sun4i_gpadc_iio *info)
Post by Philipp Rossak
static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info)
{
u32 value;
+ sunxi_calibrate(info);
if (info->data->ctrl0_map)
regmap_write(info->regmap, SUNXI_THS_CTRL0,
@@ -602,6 +622,9 @@ static int sun4i_gpadc_probe_dt(struct
platform_device *pdev,
Post by Philipp Rossak
struct resource *mem;
void __iomem *base;
int ret;
+ struct nvmem_cell *cell;
+ ssize_t cell_size;
+ u64 *cell_data;
info->data = of_device_get_match_data(&pdev->dev);
if (!info->data)
@@ -616,6 +639,35 @@ static int sun4i_gpadc_probe_dt(struct
platform_device *pdev,
Post by Philipp Rossak
if (IS_ERR(base))
return PTR_ERR(base);
+ info->has_calibration_data[0] = false;
+ info->has_calibration_data[1] = false;
+
+ if (!info->data->supports_nvmem)
+ goto no_nvmem;
+
+ cell = devm_nvmem_cell_get(&pdev->dev, "calibration");
+ if (IS_ERR(cell)) {
+ if (PTR_ERR(cell) == -EPROBE_DEFER)
+ return PTR_ERR(cell);
Use a goto here to no_nvmem.
Then you can drop the below else to make things more readable.
Post by Philipp Rossak
+ } else {
+ cell_data = (u64 *)nvmem_cell_read(cell, &cell_size);
+ devm_nvmem_cell_put(&pdev->dev, cell);
I'm really not keen on use of devm for things we are intending
to drop almost immediately. Just use the non managed versions
and clean up properly in the error paths (if there are any
where it is needed - which there aren't that I can see)
^^ Ok, I will rework that.
Post by Philipp Rossak
+ if (cell_size <= 4) {
Is it valid if it is anything other than 4?
For sensors with only one sensor would be also a 2 valid, for those with
2 sensors ==> 4, with 3 sensors ==> 6 and with and with 4 sensors ==> 8.
In hardware we have in total to 32bit registers for calibration, thus I
thought it would be a good idea to use always four bytes per register.
If two bytes are used, they should be the default value.
But I agree, this needs a rework.
Post by Philipp Rossak
+ info->has_calibration_data[0] = true;
+ info->calibration_data[0] = be32_to_cpu(cell_data[0] &
+ GENMASK(31, 0));
Masking isn't needed, If you want to be paranoid there is the
lower_32_bits
function..
^^ Ok, I will rework that.
Post by Philipp Rossak
+ } else if (cell_size <= 8) {
+ info->has_calibration_data[0] = true;
+ info->calibration_data[0] = be32_to_cpu(cell_data[0] &
+ GENMASK(31, 0));
This first block is repeated. Easy enough to avoid I think...
^^ Ok, I will rework that.
Post by Philipp Rossak
+ info->has_calibration_data[1] = true;
+ info->calibration_data[1] = be32_to_cpu(
+ (cell_data[0] >> 32) & GENMASK(31, 0));
+ }
+ }
+
+
info->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&sun4i_gpadc_regmap_config);
if (IS_ERR(info->regmap)) {
diff --git a/include/linux/mfd/sun4i-gpadc.h
b/include/linux/mfd/sun4i-gpadc.h
Post by Philipp Rossak
index 40b4dd9d2405..c251002431bd 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -90,6 +90,8 @@
#define SUNXI_THS_CTRL0 0x00
#define SUNXI_THS_CTRL2 0x40
#define SUNXI_THS_FILTER 0x70
+#define SUNXI_THS_CDATA_0_1 0x74
+#define SUNXI_THS_CDATA_2_3 0x78
#define SUNXI_THS_TDATA0 0x80
#define SUNXI_THS_TDATA1 0x84
#define SUNXI_THS_TDATA2 0x88
Thanks,
Philipp
_______________________________________________
linux-arm-kernel mailing list
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:33 UTC
Permalink
This patch rewors the driver to support interrupts for the thermal part
of the sensor.

This is only available for the newer sensor (currently H3 and A83T).
The interrupt will be trigerd on data available and triggers the update
for the thermal sensors. All newer sensors have different amount of
sensors and different interrupts for each device the reset of the
interrupts need to be done different

For the newer sensors is the autosuspend disabled.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
drivers/iio/adc/sun4i-gpadc-iio.c | 68 +++++++++++++++++++++++++++++++++++----
include/linux/mfd/sun4i-gpadc.h | 33 +++++++++++++++++++
2 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 7b12666cdd9e..77e07f042730 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -78,11 +78,14 @@ struct gpadc_data {
u32 ctrl2_map;
u32 sensor_en_map;
u32 filter_map;
+ u32 irq_clear_map;
+ u32 irq_control_map;
bool has_bus_clk;
bool has_bus_rst;
bool has_mod_clk;
int sensor_count;
bool supports_nvmem;
+ bool support_irq;
};

static const struct gpadc_data sun4i_gpadc_data = {
@@ -97,6 +100,7 @@ static const struct gpadc_data sun4i_gpadc_data = {
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
.supports_nvmem = false,
+ .support_irq = false,
};

static const struct gpadc_data sun5i_gpadc_data = {
@@ -111,6 +115,7 @@ static const struct gpadc_data sun5i_gpadc_data = {
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
.supports_nvmem = false,
+ .support_irq = false,
};

static const struct gpadc_data sun6i_gpadc_data = {
@@ -125,6 +130,7 @@ static const struct gpadc_data sun6i_gpadc_data = {
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
.supports_nvmem = false,
+ .support_irq = false,
};

static const struct gpadc_data sun8i_a33_gpadc_data = {
@@ -136,6 +142,7 @@ static const struct gpadc_data sun8i_a33_gpadc_data = {
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
.supports_nvmem = false,
+ .support_irq = false,
};

struct sun4i_gpadc_iio {
@@ -339,6 +346,11 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
return 0;
}

+ if (info->data->support_irq) {
+ regmap_read(info->regmap, info->data->temp_data[sensor], val);
+ return 0;
+ }
+
return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
}

@@ -436,6 +448,17 @@ static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}

+static irqreturn_t sunxi_irq_thread(int irq, void *data)
+{
+ struct sun4i_gpadc_iio *info = data;
+
+ regmap_write(info->regmap, SUNXI_THS_STAT, info->data->irq_clear_map);
+
+ thermal_zone_device_update(info->tzd, THERMAL_EVENT_TEMP_SAMPLE);
+
+ return IRQ_HANDLED;
+}
+
static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)
{
/* Disable the ADC on IP */
@@ -448,6 +471,8 @@ static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)

static int sunxi_ths_sample_end(struct sun4i_gpadc_iio *info)
{
+ /* Disable ths interrupt*/
+ regmap_write(info->regmap, SUNXI_THS_INTC, 0x0);
/* Disable temperature sensor */
regmap_write(info->regmap, SUNXI_THS_CTRL2, 0x0);

@@ -509,9 +534,15 @@ static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info)
regmap_write(info->regmap, SUNXI_THS_CTRL2,
info->data->ctrl2_map);

+ regmap_write(info->regmap, SUNXI_THS_STAT,
+ info->data->irq_clear_map);
+
regmap_write(info->regmap, SUNXI_THS_FILTER,
info->data->filter_map);

+ regmap_write(info->regmap, SUNXI_THS_INTC,
+ info->data->irq_control_map);
+
regmap_read(info->regmap, SUNXI_THS_CTRL2, &value);

regmap_write(info->regmap, SUNXI_THS_CTRL2,
@@ -625,12 +656,29 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
struct nvmem_cell *cell;
ssize_t cell_size;
u64 *cell_data;
+ int irq;

info->data = of_device_get_match_data(&pdev->dev);
if (!info->data)
return -ENODEV;

- info->no_irq = true;
+ if (info->data->support_irq) {
+ /* only the new versions of ths support right now irqs */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ sunxi_irq_thread, IRQF_ONESHOT,
+ dev_name(&pdev->dev), info);
+ if (ret)
+ return ret;
+
+ } else
+ info->no_irq = true;
+
indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels);
indio_dev->channels = sun8i_a33_gpadc_channels;

@@ -840,11 +888,13 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
if (ret)
return ret;

- pm_runtime_set_autosuspend_delay(&pdev->dev,
- SUN4I_GPADC_AUTOSUSPEND_DELAY);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
+ if (!info->data->support_irq) {
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ SUN4I_GPADC_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ }

if (IS_ENABLED(CONFIG_THERMAL_OF)) {
for (i = 0; i < info->data->sensor_count; i++) {
@@ -865,6 +915,9 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
}
}

+ if (info->data->support_irq)
+ info->data->sample_start(info);
+
ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "could not register the device\n");
@@ -894,6 +947,9 @@ static int sun4i_gpadc_remove(struct platform_device *pdev)
if (!IS_ENABLED(CONFIG_THERMAL_OF))
return 0;

+ if (info->data->support_irq)
+ info->data->sample_end(info);
+
thermal_zone_of_sensor_unregister(info->sensor_device, info->tzd);

if (!info->no_irq)
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index c251002431bd..ab34a96a7ff3 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -89,6 +89,8 @@
/* SUNXI_THS COMMON REGISTERS + DEFINES */
#define SUNXI_THS_CTRL0 0x00
#define SUNXI_THS_CTRL2 0x40
+#define SUNXI_THS_INTC 0x44
+#define SUNXI_THS_STAT 0x48
#define SUNXI_THS_FILTER 0x70
#define SUNXI_THS_CDATA_0_1 0x74
#define SUNXI_THS_CDATA_2_3 0x78
@@ -107,6 +109,37 @@
#define SUNXI_THS_TEMP_SENSE_EN2 BIT(2)
#define SUNXI_THS_TEMP_SENSE_EN3 BIT(3)

+#define SUNXI_THS_TEMP_PERIOD(x) (GENMASK(31, 12) & ((x) << 12))
+
+#define SUNXI_THS_INTS_ALARM_OFF_2 BIT(14)
+#define SUNXI_THS_INTS_ALARM_OFF_1 BIT(13)
+#define SUNXI_THS_INTS_ALARM_OFF_0 BIT(12)
+#define SUNXI_THS_INTS_TDATA_IRQ_3 BIT(11)
+#define SUNXI_THS_INTS_TDATA_IRQ_2 BIT(10)
+#define SUNXI_THS_INTS_TDATA_IRQ_1 BIT(9)
+#define SUNXI_THS_INTS_TDATA_IRQ_0 BIT(8)
+#define SUNXI_THS_INTS_SHUT_INT_3 BIT(7)
+#define SUNXI_THS_INTS_SHUT_INT_2 BIT(6)
+#define SUNXI_THS_INTS_SHUT_INT_1 BIT(5)
+#define SUNXI_THS_INTS_SHUT_INT_0 BIT(4)
+#define SUNXI_THS_INTS_ALARM_INT_3 BIT(3)
+#define SUNXI_THS_INTS_ALARM_INT_2 BIT(2)
+#define SUNXI_THS_INTS_ALARM_INT_1 BIT(1)
+#define SUNXI_THS_INTS_ALARM_INT_0 BIT(0)
+
+#define SUNXI_THS_INTC_TDATA_IRQ_EN3 BIT(11)
+#define SUNXI_THS_INTC_TDATA_IRQ_EN2 BIT(10)
+#define SUNXI_THS_INTC_TDATA_IRQ_EN1 BIT(9)
+#define SUNXI_THS_INTC_TDATA_IRQ_EN0 BIT(8)
+#define SUNXI_THS_INTC_SHUT_INT_EN3 BIT(7)
+#define SUNXI_THS_INTC_SHUT_INT_EN2 BIT(6)
+#define SUNXI_THS_INTC_SHUT_INT_EN1 BIT(5)
+#define SUNXI_THS_INTC_SHUT_INT_EN0 BIT(4)
+#define SUNXI_THS_INTC_ALARM_INT_EN3 BIT(3)
+#define SUNXI_THS_INTC_ALARM_INT_EN2 BIT(2)
+#define SUNXI_THS_INTC_ALARM_INT_EN1 BIT(1)
+#define SUNXI_THS_INTC_ALARM_INT_EN0 BIT(0)
+
#define MAX_SENSOR_COUNT 4

struct sun4i_gpadc_dev {
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-28 13:48:58 UTC
Permalink
On Fri, 26 Jan 2018 16:19:33 +0100
Post by Philipp Rossak
This patch rewors the driver to support interrupts for the thermal part
of the sensor.
This is only available for the newer sensor (currently H3 and A83T).
The interrupt will be trigerd on data available and triggers the update
for the thermal sensors. All newer sensors have different amount of
sensors and different interrupts for each device the reset of the
interrupts need to be done different
For the newer sensors is the autosuspend disabled.
Really minor point inline, otherwise this looks fine to me.
Post by Philipp Rossak
---
drivers/iio/adc/sun4i-gpadc-iio.c | 68 +++++++++++++++++++++++++++++++++++----
include/linux/mfd/sun4i-gpadc.h | 33 +++++++++++++++++++
2 files changed, 95 insertions(+), 6 deletions(-)
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 7b12666cdd9e..77e07f042730 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -78,11 +78,14 @@ struct gpadc_data {
u32 ctrl2_map;
u32 sensor_en_map;
u32 filter_map;
+ u32 irq_clear_map;
+ u32 irq_control_map;
bool has_bus_clk;
bool has_bus_rst;
bool has_mod_clk;
int sensor_count;
bool supports_nvmem;
+ bool support_irq;
};
static const struct gpadc_data sun4i_gpadc_data = {
@@ -97,6 +100,7 @@ static const struct gpadc_data sun4i_gpadc_data = {
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
.supports_nvmem = false,
+ .support_irq = false,
};
static const struct gpadc_data sun5i_gpadc_data = {
@@ -111,6 +115,7 @@ static const struct gpadc_data sun5i_gpadc_data = {
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
.supports_nvmem = false,
+ .support_irq = false,
};
static const struct gpadc_data sun6i_gpadc_data = {
@@ -125,6 +130,7 @@ static const struct gpadc_data sun6i_gpadc_data = {
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
.supports_nvmem = false,
+ .support_irq = false,
};
static const struct gpadc_data sun8i_a33_gpadc_data = {
@@ -136,6 +142,7 @@ static const struct gpadc_data sun8i_a33_gpadc_data = {
.sample_end = sun4i_gpadc_sample_end,
.sensor_count = 1,
.supports_nvmem = false,
+ .support_irq = false,
};
struct sun4i_gpadc_iio {
@@ -339,6 +346,11 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
return 0;
}
+ if (info->data->support_irq) {
+ regmap_read(info->regmap, info->data->temp_data[sensor], val);
+ return 0;
+ }
+
return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
}
@@ -436,6 +448,17 @@ static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t sunxi_irq_thread(int irq, void *data)
+{
+ struct sun4i_gpadc_iio *info = data;
+
+ regmap_write(info->regmap, SUNXI_THS_STAT, info->data->irq_clear_map);
+
+ thermal_zone_device_update(info->tzd, THERMAL_EVENT_TEMP_SAMPLE);
+
+ return IRQ_HANDLED;
+}
+
static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)
{
/* Disable the ADC on IP */
@@ -448,6 +471,8 @@ static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)
static int sunxi_ths_sample_end(struct sun4i_gpadc_iio *info)
{
+ /* Disable ths interrupt*/
Space before */
^^ Ok, I will rework that.
Post by Philipp Rossak
+ regmap_write(info->regmap, SUNXI_THS_INTC, 0x0);
/* Disable temperature sensor */
regmap_write(info->regmap, SUNXI_THS_CTRL2, 0x0);
@@ -509,9 +534,15 @@ static int sunxi_ths_sample_start(struct sun4i_gpadc_iio *info)
regmap_write(info->regmap, SUNXI_THS_CTRL2,
info->data->ctrl2_map);
+ regmap_write(info->regmap, SUNXI_THS_STAT,
+ info->data->irq_clear_map);
+
regmap_write(info->regmap, SUNXI_THS_FILTER,
info->data->filter_map);
+ regmap_write(info->regmap, SUNXI_THS_INTC,
+ info->data->irq_control_map);
+
regmap_read(info->regmap, SUNXI_THS_CTRL2, &value);
regmap_write(info->regmap, SUNXI_THS_CTRL2,
@@ -625,12 +656,29 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
struct nvmem_cell *cell;
ssize_t cell_size;
u64 *cell_data;
+ int irq;
info->data = of_device_get_match_data(&pdev->dev);
if (!info->data)
return -ENODEV;
- info->no_irq = true;
+ if (info->data->support_irq) {
+ /* only the new versions of ths support right now irqs */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ sunxi_irq_thread, IRQF_ONESHOT,
+ dev_name(&pdev->dev), info);
+ if (ret)
+ return ret;
+
+ } else
+ info->no_irq = true;
+
indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels);
indio_dev->channels = sun8i_a33_gpadc_channels;
@@ -840,11 +888,13 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
if (ret)
return ret;
- pm_runtime_set_autosuspend_delay(&pdev->dev,
- SUN4I_GPADC_AUTOSUSPEND_DELAY);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
+ if (!info->data->support_irq) {
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ SUN4I_GPADC_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ }
if (IS_ENABLED(CONFIG_THERMAL_OF)) {
for (i = 0; i < info->data->sensor_count; i++) {
@@ -865,6 +915,9 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
}
}
+ if (info->data->support_irq)
+ info->data->sample_start(info);
+
ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "could not register the device\n");
@@ -894,6 +947,9 @@ static int sun4i_gpadc_remove(struct platform_device *pdev)
if (!IS_ENABLED(CONFIG_THERMAL_OF))
return 0;
+ if (info->data->support_irq)
+ info->data->sample_end(info);
+
thermal_zone_of_sensor_unregister(info->sensor_device, info->tzd);
if (!info->no_irq)
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index c251002431bd..ab34a96a7ff3 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -89,6 +89,8 @@
/* SUNXI_THS COMMON REGISTERS + DEFINES */
#define SUNXI_THS_CTRL0 0x00
#define SUNXI_THS_CTRL2 0x40
+#define SUNXI_THS_INTC 0x44
+#define SUNXI_THS_STAT 0x48
#define SUNXI_THS_FILTER 0x70
#define SUNXI_THS_CDATA_0_1 0x74
#define SUNXI_THS_CDATA_2_3 0x78
@@ -107,6 +109,37 @@
#define SUNXI_THS_TEMP_SENSE_EN2 BIT(2)
#define SUNXI_THS_TEMP_SENSE_EN3 BIT(3)
+#define SUNXI_THS_TEMP_PERIOD(x) (GENMASK(31, 12) & ((x) << 12))
+
+#define SUNXI_THS_INTS_ALARM_OFF_2 BIT(14)
+#define SUNXI_THS_INTS_ALARM_OFF_1 BIT(13)
+#define SUNXI_THS_INTS_ALARM_OFF_0 BIT(12)
+#define SUNXI_THS_INTS_TDATA_IRQ_3 BIT(11)
+#define SUNXI_THS_INTS_TDATA_IRQ_2 BIT(10)
+#define SUNXI_THS_INTS_TDATA_IRQ_1 BIT(9)
+#define SUNXI_THS_INTS_TDATA_IRQ_0 BIT(8)
+#define SUNXI_THS_INTS_SHUT_INT_3 BIT(7)
+#define SUNXI_THS_INTS_SHUT_INT_2 BIT(6)
+#define SUNXI_THS_INTS_SHUT_INT_1 BIT(5)
+#define SUNXI_THS_INTS_SHUT_INT_0 BIT(4)
+#define SUNXI_THS_INTS_ALARM_INT_3 BIT(3)
+#define SUNXI_THS_INTS_ALARM_INT_2 BIT(2)
+#define SUNXI_THS_INTS_ALARM_INT_1 BIT(1)
+#define SUNXI_THS_INTS_ALARM_INT_0 BIT(0)
+
+#define SUNXI_THS_INTC_TDATA_IRQ_EN3 BIT(11)
+#define SUNXI_THS_INTC_TDATA_IRQ_EN2 BIT(10)
+#define SUNXI_THS_INTC_TDATA_IRQ_EN1 BIT(9)
+#define SUNXI_THS_INTC_TDATA_IRQ_EN0 BIT(8)
+#define SUNXI_THS_INTC_SHUT_INT_EN3 BIT(7)
+#define SUNXI_THS_INTC_SHUT_INT_EN2 BIT(6)
+#define SUNXI_THS_INTC_SHUT_INT_EN1 BIT(5)
+#define SUNXI_THS_INTC_SHUT_INT_EN0 BIT(4)
+#define SUNXI_THS_INTC_ALARM_INT_EN3 BIT(3)
+#define SUNXI_THS_INTC_ALARM_INT_EN2 BIT(2)
+#define SUNXI_THS_INTC_ALARM_INT_EN1 BIT(1)
+#define SUNXI_THS_INTC_ALARM_INT_EN0 BIT(0)
+
#define MAX_SENSOR_COUNT 4
struct sun4i_gpadc_dev {
Thanks,
Philipp
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:34 UTC
Permalink
This patch adds support for the H3 ths sensor.

The H3 supports interrupts. The interrupt is configured to update the
the sensor values every second. The calibration data is writen at the
begin of the init process.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
drivers/iio/adc/sun4i-gpadc-iio.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 77e07f042730..f2e0ec65c53e 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -145,6 +145,31 @@ static const struct gpadc_data sun8i_a33_gpadc_data = {
.support_irq = false,
};

+static const struct gpadc_data sun8i_h3_ths_data = {
+ .temp_offset = -1791,
+ .temp_scale = -121,
+ .temp_data = {SUNXI_THS_TDATA0, 0, 0, 0},
+ .sample_start = sunxi_ths_sample_start,
+ .sample_end = sunxi_ths_sample_end,
+ .has_bus_clk = true,
+ .has_bus_rst = true,
+ .has_mod_clk = true,
+ .sensor_count = 1,
+ .supports_nvmem = true,
+ .support_irq = true,
+ .ctrl0_map = SUNXI_THS_ACQ0(0xff),
+ .ctrl2_map = SUNXI_THS_ACQ1(0x3f),
+ .sensor_en_map = SUNXI_THS_TEMP_SENSE_EN0,
+ .filter_map = SUNXI_THS_FILTER_EN |
+ SUNXI_THS_FILTER_TYPE(0x2),
+ .irq_clear_map = SUNXI_THS_INTS_ALARM_INT_0 |
+ SUNXI_THS_INTS_SHUT_INT_0 |
+ SUNXI_THS_INTS_TDATA_IRQ_0 |
+ SUNXI_THS_INTS_ALARM_OFF_0,
+ .irq_control_map = SUNXI_THS_INTC_TDATA_IRQ_EN0 |
+ SUNXI_THS_TEMP_PERIOD(0x7),
+};
+
struct sun4i_gpadc_iio {
struct iio_dev *indio_dev;
struct completion completion;
@@ -643,6 +668,10 @@ static const struct of_device_id sun4i_gpadc_of_id[] = {
.compatible = "allwinner,sun8i-a33-ths",
.data = &sun8i_a33_gpadc_data,
},
+ {
+ .compatible = "allwinner,sun8i-h3-ths",
+ .data = &sun8i_h3_ths_data,
+ },
{ /* sentinel */ }
};
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:35 UTC
Permalink
This patch adds support for the A83T ths sensor.

The A83T does not support interrupts. This seems to be broken.
The calibration data is writen at the begin of the init process.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
drivers/iio/adc/sun4i-gpadc-iio.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index f2e0ec65c53e..b8693afcdbea 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -170,6 +170,40 @@ static const struct gpadc_data sun8i_h3_ths_data = {
SUNXI_THS_TEMP_PERIOD(0x7),
};

+static const struct gpadc_data sun8i_a83t_ths_data = {
+ .temp_offset = -2724,
+ .temp_scale = -70,
+ .temp_data = {SUNXI_THS_TDATA0,
+ SUNXI_THS_TDATA1,
+ SUNXI_THS_TDATA2,
+ 0},
+ .sample_start = sunxi_ths_sample_start,
+ .sample_end = sunxi_ths_sample_end,
+ .sensor_count = 3,
+ .supports_nvmem = false,
+ .support_irq = true,
+ .ctrl0_map = SUNXI_THS_ACQ0(0x1f3),
+ .ctrl2_map = SUNXI_THS_ACQ1(0x1f3),
+ .sensor_en_map = SUNXI_THS_TEMP_SENSE_EN0 |
+ SUNXI_THS_TEMP_SENSE_EN1 |
+ SUNXI_THS_TEMP_SENSE_EN2,
+ .filter_map = SUNXI_THS_FILTER_EN |
+ SUNXI_THS_FILTER_TYPE(0x2),
+ .irq_clear_map = SUNXI_THS_INTS_ALARM_INT_0 |
+ SUNXI_THS_INTS_ALARM_INT_1 |
+ SUNXI_THS_INTS_ALARM_INT_2 |
+ SUNXI_THS_INTS_SHUT_INT_0 |
+ SUNXI_THS_INTS_SHUT_INT_1 |
+ SUNXI_THS_INTS_SHUT_INT_2 |
+ SUNXI_THS_INTS_TDATA_IRQ_0 |
+ SUNXI_THS_INTS_TDATA_IRQ_1 |
+ SUNXI_THS_INTS_TDATA_IRQ_2,
+ .irq_control_map = SUNXI_THS_INTC_TDATA_IRQ_EN0 |
+ SUNXI_THS_INTC_TDATA_IRQ_EN1 |
+ SUNXI_THS_INTC_TDATA_IRQ_EN2 |
+ SUNXI_THS_TEMP_PERIOD(0x257),
+};
+
struct sun4i_gpadc_iio {
struct iio_dev *indio_dev;
struct completion completion;
@@ -672,6 +706,10 @@ static const struct of_device_id sun4i_gpadc_of_id[] = {
.compatible = "allwinner,sun8i-h3-ths",
.data = &sun8i_h3_ths_data,
},
+ {
+ .compatible = "allwinner,sun8i-a83t-ths",
+ .data = &sun8i_a83t_ths_data,
+ },
{ /* sentinel */ }
};
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-27 04:30:36 UTC
Permalink
Hi,
Post by Philipp Rossak
This patch adds support for the A83T ths sensor.
The A83T does not support interrupts. This seems to be broken.
Though, you use support_irq = true below. And in my tests, IRQ for THS works on
A83T.
regards,
o.
Oh I totally forgot to update this commit message, after I fixed the
devicetree and got it running.
I will fix that in the next version of this patch series.
Post by Philipp Rossak
The calibration data is writen at the begin of the init process.
---
drivers/iio/adc/sun4i-gpadc-iio.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index f2e0ec65c53e..b8693afcdbea 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -170,6 +170,40 @@ static const struct gpadc_data sun8i_h3_ths_data = {
SUNXI_THS_TEMP_PERIOD(0x7),
};
+static const struct gpadc_data sun8i_a83t_ths_data = {
+ .temp_offset = -2724,
+ .temp_scale = -70,
+ .temp_data = {SUNXI_THS_TDATA0,
+ SUNXI_THS_TDATA1,
+ SUNXI_THS_TDATA2,
+ 0},
+ .sample_start = sunxi_ths_sample_start,
+ .sample_end = sunxi_ths_sample_end,
+ .sensor_count = 3,
+ .supports_nvmem = false,
+ .support_irq = true,
+ .ctrl0_map = SUNXI_THS_ACQ0(0x1f3),
+ .ctrl2_map = SUNXI_THS_ACQ1(0x1f3),
+ .sensor_en_map = SUNXI_THS_TEMP_SENSE_EN0 |
+ SUNXI_THS_TEMP_SENSE_EN1 |
+ SUNXI_THS_TEMP_SENSE_EN2,
+ .filter_map = SUNXI_THS_FILTER_EN |
+ SUNXI_THS_FILTER_TYPE(0x2),
+ .irq_clear_map = SUNXI_THS_INTS_ALARM_INT_0 |
+ SUNXI_THS_INTS_ALARM_INT_1 |
+ SUNXI_THS_INTS_ALARM_INT_2 |
+ SUNXI_THS_INTS_SHUT_INT_0 |
+ SUNXI_THS_INTS_SHUT_INT_1 |
+ SUNXI_THS_INTS_SHUT_INT_2 |
+ SUNXI_THS_INTS_TDATA_IRQ_0 |
+ SUNXI_THS_INTS_TDATA_IRQ_1 |
+ SUNXI_THS_INTS_TDATA_IRQ_2,
+ .irq_control_map = SUNXI_THS_INTC_TDATA_IRQ_EN0 |
+ SUNXI_THS_INTC_TDATA_IRQ_EN1 |
+ SUNXI_THS_INTC_TDATA_IRQ_EN2 |
+ SUNXI_THS_TEMP_PERIOD(0x257),
+};
+
struct sun4i_gpadc_iio {
struct iio_dev *indio_dev;
struct completion completion;
@@ -672,6 +706,10 @@ static const struct of_device_id sun4i_gpadc_of_id[] = {
.compatible = "allwinner,sun8i-h3-ths",
.data = &sun8i_h3_ths_data,
},
+ {
+ .compatible = "allwinner,sun8i-a83t-ths",
+ .data = &sun8i_a83t_ths_data,
+ },
{ /* sentinel */ }
};
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
For more options, visit https://groups.google.com/d/optout.
Thanks,
Philipp
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:36 UTC
Permalink
As we have gained the support for the thermal sensor in H3 and H5,
we can now add its device nodes to the device tree. The H3 and H5 share
most of its compatible. The compatible and the thermal sensor cells
will be added in an additional patch per device.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 7a83b15225c7..413c789b588d 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -426,6 +426,15 @@
};
};

+ ths: thermal-***@1c25000 {
+ reg = <0x01c25000 0x100>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
+ clock-names = "bus", "mod";
+ resets = <&ccu RST_BUS_THS>;
+ #io-channel-cells = <0>;
+ };
+
***@1c20c00 {
compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0xa0>;
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:37 UTC
Permalink
This patch adds the missing compatible and the thermal sensor cells.
The H3 has one sensor.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 8495deecedad..fbb007e5798e 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -128,3 +128,8 @@
&pio {
compatible = "allwinner,sun8i-h3-pinctrl";
};
+
+&ths {
+ compatible = "allwinner,sun8i-h3-ths";
+ #thermal-sensor-cells = <0>;
+};
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:38 UTC
Permalink
This patch adds the thermal zones to the H3. We have only one sensor and
that is placed in the cpu.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index fbb007e5798e..3f83f6a27c74 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -72,6 +72,15 @@
};
};

+ thermal-zones {
+ cpu-thermal {
+ /* milliseconds */
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths 0>;
+ };
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Samuel Holland
2018-01-26 16:26:19 UTC
Permalink
Post by Philipp Rossak
This patch adds the thermal zones to the H3. We have only one sensor and
that is placed in the cpu.
---
arch/arm/boot/dts/sun8i-h3.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index fbb007e5798e..3f83f6a27c74 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -72,6 +72,15 @@
};
};
+ thermal-zones {
+ cpu-thermal {
+ /* milliseconds */
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths 0>;
If #thermal-sensor-cells = <0>, shouldn't this just be <&ths> ?
Post by Philipp Rossak
+ };
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
Thanks,
Samuel
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 17:48:39 UTC
Permalink
Post by Samuel Holland
Post by Philipp Rossak
This patch adds the thermal zones to the H3. We have only one sensor and
that is placed in the cpu.
---
arch/arm/boot/dts/sun8i-h3.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index fbb007e5798e..3f83f6a27c74 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -72,6 +72,15 @@
};
};
+ thermal-zones {
+ cpu-thermal {
+ /* milliseconds */
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths 0>;
If #thermal-sensor-cells = <0>, shouldn't this just be <&ths> ?
I think both works, but I my intention was to have an accurate
description in DT.
I thought that that is important in DT.
Post by Samuel Holland
Post by Philipp Rossak
+ };
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
Thanks,
Samuel
Regards,
Philipp
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:39 UTC
Permalink
This patch enables the the sid controller in the H3. It can be used
for thermal calibration data.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 3f83f6a27c74..9bb5cc29fec5 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -72,6 +72,13 @@
};
};

+ soc {
+ sid: ***@1c14000 {
+ compatible = "allwinner,sun8i-h3-sid";
+ reg = <0x01c14000 0x400>;
+ };
+ };
+
thermal-zones {
cpu-thermal {
/* milliseconds */
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:40 UTC
Permalink
As we have gained the support for the thermal sensor in A83T,
we can now add its device nodes to the device tree.

The A83T seems to have a broken IRQ 31, thus we use here IRQ 41.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 7f4955a5fab7..9e53ff5ac4ed 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -518,6 +518,14 @@
clocks = <&osc24M>;
};

+ ths: thermal-***@1f04000 {
+ compatible = "allwinner,sun8i-a83t-ths";
+ reg = <0x01f04000 0x100>;
+ interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ #thermal-sensor-cells = <1>;
+ #io-channel-cells = <0>;
+ };
+
***@1c20ca0 {
compatible = "allwinner,sun6i-a31-wdt";
reg = <0x01c20ca0 0x20>;
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 15:19:41 UTC
Permalink
This patch adds the thermal zones to the A83T. Sensor 0 is located in the
cpu cluster 0. Sensor 1 is located in cluster 1 and Sensor 3 is located
in the gpu.

Signed-off-by: Philipp Rossak <***@gmail.com>
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 9e53ff5ac4ed..4259a8726031 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -747,4 +747,24 @@
#size-cells = <0>;
};
};
+
+ thermal-zones {
+ cpu0_thermal: cpu0-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&ths 0>;
+ };
+
+ cpu1_thermal: cpu1-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&ths 1>;
+ };
+
+ gpu_thermal: gpu-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&ths 2>;
+ };
+ };
};
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Samuel Holland
2018-01-26 16:25:12 UTC
Permalink
Post by Philipp Rossak
This patch adds the thermal zones to the A83T. Sensor 0 is located in the
cpu cluster 0. Sensor 1 is located in cluster 1 and Sensor 3 is located
in the gpu.
You mention sensor 3 here, but have sensor 2 in the device tree.
Post by Philipp Rossak
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 9e53ff5ac4ed..4259a8726031 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -747,4 +747,24 @@
#size-cells = <0>;
};
};
+
+ thermal-zones {
+ cpu0_thermal: cpu0-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&ths 0>;
+ };
+
+ cpu1_thermal: cpu1-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&ths 1>;
+ };
+
+ gpu_thermal: gpu-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&ths 2>;
^^^^ here
Post by Philipp Rossak
+ };
+ };
};
Thanks,
Samuel
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Philipp Rossak
2018-01-26 17:35:38 UTC
Permalink
Post by Samuel Holland
Post by Philipp Rossak
This patch adds the thermal zones to the A83T. Sensor 0 is located in the
cpu cluster 0. Sensor 1 is located in cluster 1 and Sensor 3 is located
in the gpu.
You mention sensor 3 here, but have sensor 2 in the device tree.
That is a typo/wrong counting error. This should be sensor 2.

I will fix that in the next version of this patch series.
Post by Samuel Holland
Post by Philipp Rossak
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 9e53ff5ac4ed..4259a8726031 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -747,4 +747,24 @@
#size-cells = <0>;
};
};
+
+ thermal-zones {
+ cpu0_thermal: cpu0-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&ths 0>;
+ };
+
+ cpu1_thermal: cpu1-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&ths 1>;
+ };
+
+ gpu_thermal: gpu-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&ths 2>;
^^^^ here
Post by Philipp Rossak
+ };
+ };
};
Thanks,
Samuel
Thanks,
Philipp
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Petr Malanik
2018-02-01 22:43:14 UTC
Permalink
Hi,
in function sun4i_gpadc_probe_dt is still channel structure which
corresponds to a33 channels. So if you use this driver for a83t you can
only read first channel from sysfs. Shouldn't be this channel structure
also in gpadc_data structure?

indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels);
indio_dev->channels = sun8i_a33_gpadc_channels;

Thanks,
Petr Malaník
Allwiner H3 and A83T SoCs have a thermal sensor, which is a large
refactored
version of the old Allwinner "GPADC" (although it have already only
thermal part left in A33).
This patch tried to add support for the sensor in H3 and A83T based on
the A33 thermal sensor driver by Quentin Schulz, which is already merged.
This Patchseries is based on Icenowy Zhengs v4 patchseries [1].
The first 5 patches are reworked patches from the v4 patchseries.
The rest of the patches add step by step a feature to support multible
sensors, nvmem calibration and interupts. This patchseries should make it
easy also to add other sunxi SoCs, like the H5, A64 and A80.
Patches that adds support for H5, A64 and A80 SoCs are allready prepared,
and will be upstreamed if this patchseries is applied and the testing is
done.
I tried to pick up all the feedback from [1]. I hope I didn't miss
anything.
Regards,
Philipp
[1]: https://lkml.org/lkml/2017/9/14/317
iio: adc: sun4i-gpadc-iio: rename A33-specified registers to contain
A33
dt-bindings: update the Allwinner GPADC device tree binding for H3 &
A83T
arm: config: sunxi_defconfig: enable SUN4I_GPADC
iio: adc: sun4i-gpadc-iio: rework: sampling start/end code readout reg
iio: adc: sun4i-gpadc-iio: rework: support clocks and reset
iio: adc: sun4i-gpadc-iio: rework: support multible sensors
iio: adc: sun4i-gpadc-iio: rework: support nvmem calibration data
iio: adc: sun4i-gpadc-iio: rework: add interrupt support
iio: adc: sun4i-gpadc-iio: add support for H3 thermal sensor
iio: adc: sun4i-gpadc-iio: add support for A83T thermal sensor
arm: dts: sunxi-h3-h5: add support for the thermal sensor in H3 and H5
arm: dts: sun8i: h3: add support for the thermal sensor in H3
arm: dts: sun8i: h3: add thermal zone to H3
arm: dts: sun8i: h3: enable H3 sid controller
arm: dts: sun8i: a83t: add support for the thermal sensor in A83T
arm: dts: sun8i: a83t: add thermal zone to A83T
.../devicetree/bindings/mfd/sun4i-gpadc.txt | 50 ++-
arch/arm/boot/dts/sun8i-a83t.dtsi | 28 ++
arch/arm/boot/dts/sun8i-h3.dtsi | 21 ++
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 9 +
arch/arm/configs/sunxi_defconfig | 1 +
drivers/iio/adc/sun4i-gpadc-iio.c | 378
+++++++++++++++++++--
include/linux/mfd/sun4i-gpadc.h | 66 +++-
7 files changed, 522 insertions(+), 31 deletions(-)
--
2.11.0
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...