balena-allwinner/layers/meta-balena-allwinner/recipes-kernel/linux/linux-mainline-4.19/0000-0005-thermal-sun8i-Add-support-for-A83T-thermal-sensors.patch
Vicentiu Galanopulo 065936bc48 recipes-kernel/linux: Rename linux to linux-mainline
Since the Armbian sources refer to linux 4.19.76 as
being linux-mainline, all the patches from linux-4.19
were moved to linux-mainline_4.19 and the linux_4.19.76
recipes was named accordingly.

This patch makes 4.19.76 as default version for linux

Signed-off-by: Vicentiu Galanopulo <vicentiu@balena.io>
2019-10-10 11:50:45 +02:00

498 lines
15 KiB
Diff

From 9da4c28e6a7963f67e2ca05098683445a1571538 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 14 Nov 2017 17:15:54 +0100
Subject: [PATCH 05/82] thermal: sun8i: Add support for A83T thermal sensors
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/thermal/sun8i_ths.c | 371 ++++++++++++++++++++++++++----------
1 file changed, 274 insertions(+), 97 deletions(-)
diff --git a/drivers/thermal/sun8i_ths.c b/drivers/thermal/sun8i_ths.c
index cfe7d1073b8c..2fda940da4cc 100644
--- a/drivers/thermal/sun8i_ths.c
+++ b/drivers/thermal/sun8i_ths.c
@@ -1,5 +1,5 @@
/*
- * Thermal sensor driver for Allwinner H3 SoC
+ * Thermal sensor driver for Allwinner SUN8I SoC
*
* Copyright (C) 2016 Ondřej Jirman
* Based on the work of Josef Gajdusek <atx@atx.name>
@@ -26,79 +26,174 @@
#include <linux/thermal.h>
#include <linux/printk.h>
-#define THS_H3_CTRL0 0x00
-#define THS_H3_CTRL2 0x40
-#define THS_H3_INT_CTRL 0x44
-#define THS_H3_STAT 0x48
-#define THS_H3_FILTER 0x70
-#define THS_H3_CDATA 0x74
-#define THS_H3_DATA 0x80
-
-#define THS_H3_CTRL0_SENSOR_ACQ0(x) (x)
-#define THS_H3_CTRL2_SENSE_EN BIT(0)
-#define THS_H3_CTRL2_SENSOR_ACQ1(x) ((x) << 16)
-#define THS_H3_INT_CTRL_DATA_IRQ_EN BIT(8)
-#define THS_H3_INT_CTRL_THERMAL_PER(x) ((x) << 12)
-#define THS_H3_STAT_DATA_IRQ_STS BIT(8)
-#define THS_H3_FILTER_TYPE(x) ((x) << 0)
-#define THS_H3_FILTER_EN BIT(2)
-
-#define THS_H3_CLK_IN 40000000 /* Hz */
-#define THS_H3_DATA_PERIOD 330 /* ms */
-
-#define THS_H3_FILTER_TYPE_VALUE 2 /* average over 2^(n+1) samples */
-#define THS_H3_FILTER_DIV (1 << (THS_H3_FILTER_TYPE_VALUE + 1))
-#define THS_H3_INT_CTRL_THERMAL_PER_VALUE \
- (THS_H3_DATA_PERIOD * (THS_H3_CLK_IN / 1000) / THS_H3_FILTER_DIV / 4096 - 1)
-#define THS_H3_CTRL0_SENSOR_ACQ0_VALUE 0x3f /* 16us */
-#define THS_H3_CTRL2_SENSOR_ACQ1_VALUE 0x3f
+#define THS_SUN8I_CTRL0 0x00
+#define THS_SUN8I_CTRL2 0x40
+#define THS_SUN8I_INT_CTRL 0x44
+#define THS_SUN8I_STAT 0x48
+#define THS_SUN8I_FILTER 0x70
+#define THS_SUN8I_CDATA01 0x74
+#define THS_SUN8I_CDATA2 0x78
+#define THS_SUN8I_DATA0 0x80
+#define THS_SUN8I_DATA1 0x84
+#define THS_SUN8I_DATA2 0x88
+
+#define THS_SUN8I_CTRL0_SENSOR_ACQ0(x) (x)
+#define THS_SUN8I_CTRL2_SENSE_EN0 BIT(0)
+#define THS_SUN8I_CTRL2_SENSE_EN1 BIT(1)
+#define THS_SUN8I_CTRL2_SENSE_EN2 BIT(2)
+#define THS_SUN8I_CTRL2_SENSOR_ACQ1(x) ((x) << 16)
+#define THS_SUN8I_INT_CTRL_DATA0_IRQ_EN BIT(8)
+#define THS_SUN8I_INT_CTRL_DATA1_IRQ_EN BIT(9)
+#define THS_SUN8I_INT_CTRL_DATA2_IRQ_EN BIT(10)
+#define THS_SUN8I_INT_CTRL_THERMAL_PER(x) ((x) << 12)
+#define THS_SUN8I_STAT_DATA0_IRQ_STS BIT(8)
+#define THS_SUN8I_STAT_DATA1_IRQ_STS BIT(9)
+#define THS_SUN8I_STAT_DATA2_IRQ_STS BIT(10)
+#define THS_SUN8I_STAT_CLEAR 0x777
+#define THS_SUN8I_FILTER_TYPE(x) ((x) << 0)
+#define THS_SUN8I_FILTER_EN BIT(2)
+
+#define THS_SUN8I_CLK_IN 40000000 /* Hz */
+#define THS_SUN8I_DATA_PERIOD 330 /* ms */
+#define THS_SUN8I_FILTER_TYPE_VALUE 2 /* average over 2^(n+1) samples */
+
+//XXX: this formula doesn't work for A83T very well
+//XXX: A83T is getting slower readings out of this (1s interval?)
+//perhaps configure this in sun8i_ths_desc
+#define THS_SUN8I_FILTER_DIV (1 << (THS_SUN8I_FILTER_TYPE_VALUE + 1))
+#define THS_SUN8I_INT_CTRL_THERMAL_PER_VALUE \
+ (THS_SUN8I_DATA_PERIOD * (THS_SUN8I_CLK_IN / 1000) / \
+ THS_SUN8I_FILTER_DIV / 4096 - 1)
+
+#define THS_SUN8I_CTRL0_SENSOR_ACQ0_VALUE 0x3f /* 16us */
+#define THS_SUN8I_CTRL2_SENSOR_ACQ1_VALUE 0x3f
+
+#define SUN8I_THS_MAX_TZDS 3
+
+struct sun8i_ths_sensor_desc {
+ u32 data_int_en;
+ u32 data_int_flag;
+ u32 data_offset;
+ u32 sense_en;
+};
+
+struct sun8i_ths_desc {
+ int num_sensors;
+ struct sun8i_ths_sensor_desc *sensors;
+ int (*calc_temp)(u32 reg_val);
+ bool has_cal1;
+};
+
+struct sun8i_ths_tzd {
+ struct sun8i_ths_data *data;
+ struct thermal_zone_device *tzd;
+ u32 temp;
+};
struct sun8i_ths_data {
+ struct device *dev;
struct reset_control *reset;
struct clk *clk;
struct clk *busclk;
void __iomem *regs;
- struct thermal_zone_device *tzd;
- u32 temp;
+ void __iomem *cal_regs;
+ struct sun8i_ths_desc *desc;
+ struct sun8i_ths_tzd tzds[SUN8I_THS_MAX_TZDS];
};
+static int sun8i_ths_calc_temp_h3(u32 reg_val)
+{
+ uint64_t temp = (uint64_t)reg_val * 1000000ll;
+
+ do_div(temp, 8253);
+
+ return 217000 - (int)temp;
+}
+
+static int sun8i_ths_calc_temp_a83t(u32 reg_val)
+{
+ uint64_t temp = (uint64_t)reg_val * 1000000ll;
+
+ do_div(temp, 14186);
+
+ return 192000 - (int)temp;
+}
+
static int sun8i_ths_get_temp(void *_data, int *out)
{
- struct sun8i_ths_data *data = _data;
+ struct sun8i_ths_tzd *tzd = _data;
+ struct sun8i_ths_data *data = tzd->data;
- if (data->temp == 0)
+ if (tzd->temp == 0)
return -EBUSY;
- /* Formula and parameters from the Allwinner 3.4 kernel */
- *out = 217000 - (int)((data->temp * 1000000) / 8253);
+ *out = data->desc->calc_temp(tzd->temp);
return 0;
}
static irqreturn_t sun8i_ths_irq_thread(int irq, void *_data)
{
struct sun8i_ths_data *data = _data;
-
- writel(THS_H3_STAT_DATA_IRQ_STS, data->regs + THS_H3_STAT);
-
- data->temp = readl(data->regs + THS_H3_DATA);
- if (data->temp)
- thermal_zone_device_update(data->tzd, THERMAL_EVENT_TEMP_SAMPLE);
+ struct sun8i_ths_tzd *tzd;
+ struct sun8i_ths_sensor_desc *zdesc;
+ int i;
+ u32 status;
+
+ status = readl(data->regs + THS_SUN8I_STAT);
+ writel(THS_SUN8I_STAT_CLEAR, data->regs + THS_SUN8I_STAT);
+
+ for (i = 0; i < data->desc->num_sensors; i++) {
+ tzd = &data->tzds[i];
+ zdesc = &data->desc->sensors[i];
+
+ if (status & zdesc->data_int_flag) {
+ tzd->temp = readl(data->regs + zdesc->data_offset);
+ if (tzd->temp)
+ thermal_zone_device_update(tzd->tzd,
+ THERMAL_EVENT_TEMP_SAMPLE);
+ }
+ }
return IRQ_HANDLED;
}
-static void sun8i_ths_h3_init(struct sun8i_ths_data *data)
+static void sun8i_ths_init(struct sun8i_ths_data *data)
{
- writel(THS_H3_CTRL0_SENSOR_ACQ0(THS_H3_CTRL0_SENSOR_ACQ0_VALUE),
- data->regs + THS_H3_CTRL0);
- writel(THS_H3_FILTER_EN | THS_H3_FILTER_TYPE(THS_H3_FILTER_TYPE_VALUE),
- data->regs + THS_H3_FILTER);
- writel(THS_H3_CTRL2_SENSOR_ACQ1(THS_H3_CTRL2_SENSOR_ACQ1_VALUE) |
- THS_H3_CTRL2_SENSE_EN,
- data->regs + THS_H3_CTRL2);
- writel(THS_H3_INT_CTRL_THERMAL_PER(THS_H3_INT_CTRL_THERMAL_PER_VALUE) |
- THS_H3_INT_CTRL_DATA_IRQ_EN,
- data->regs + THS_H3_INT_CTRL);
+ int i;
+ u32 int_ctrl = 0;
+ u32 ctrl2 = 0;
+
+ writel(THS_SUN8I_CTRL0_SENSOR_ACQ0(THS_SUN8I_CTRL0_SENSOR_ACQ0_VALUE),
+ data->regs + THS_SUN8I_CTRL0);
+ writel(THS_SUN8I_FILTER_EN | THS_SUN8I_FILTER_TYPE(THS_SUN8I_FILTER_TYPE_VALUE),
+ data->regs + THS_SUN8I_FILTER);
+
+ ctrl2 |= THS_SUN8I_CTRL2_SENSOR_ACQ1(THS_SUN8I_CTRL2_SENSOR_ACQ1_VALUE);
+ int_ctrl |= THS_SUN8I_INT_CTRL_THERMAL_PER(THS_SUN8I_INT_CTRL_THERMAL_PER_VALUE);
+
+ for (i = 0; i < data->desc->num_sensors; i++) {
+ ctrl2 |= data->desc->sensors[i].sense_en;
+ int_ctrl |= data->desc->sensors[i].data_int_en;
+ }
+
+ if (data->cal_regs) {
+ u32 cal0, cal1;
+
+ cal0 = readl(data->cal_regs);
+ if (cal0)
+ writel(cal0, data->regs + THS_SUN8I_CDATA01);
+
+ if (data->desc->has_cal1) {
+ cal1 = readl(data->cal_regs + 4);
+ if (cal1)
+ writel(cal1, data->regs + THS_SUN8I_CDATA2);
+ }
+ }
+
+ writel(ctrl2, data->regs + THS_SUN8I_CTRL2);
+
+ /* enable interrupts */
+ writel(int_ctrl, data->regs + THS_SUN8I_INT_CTRL);
}
static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = {
@@ -108,100 +203,135 @@ static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = {
static int sun8i_ths_probe(struct platform_device *pdev)
{
struct sun8i_ths_data *data;
+ struct device *dev = &pdev->dev;
struct resource *res;
- int ret;
- int irq;
+ int ret, irq, i;
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->desc = (struct sun8i_ths_desc *)of_device_get_match_data(dev);
+ if (data->desc == NULL)
+ return -EINVAL;
+
+ data->dev = dev;
+ platform_set_drvdata(pdev, data);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ths");
if (!res) {
- dev_err(&pdev->dev, "no memory resources defined\n");
+ dev_err(dev, "no memory resources defined\n");
return -EINVAL;
}
- data->regs = devm_ioremap_resource(&pdev->dev, res);
+ data->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(data->regs)) {
ret = PTR_ERR(data->regs);
- dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret);
+ dev_err(dev, "failed to ioremap THS registers: %d\n", ret);
return ret;
}
+ /*XXX: use SRAM device in the future, instead of direct access to regs */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "calibration");
+ if (res) {
+ data->cal_regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->cal_regs)) {
+ ret = PTR_ERR(data->cal_regs);
+ dev_err(dev, "failed to ioremap calibration SRAM: %d\n", ret);
+ return ret;
+ }
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
+ dev_err(dev, "failed to get IRQ: %d\n", irq);
return irq;
}
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ret = devm_request_threaded_irq(dev, irq, NULL,
sun8i_ths_irq_thread, IRQF_ONESHOT,
- dev_name(&pdev->dev), data);
+ dev_name(dev), data);
if (ret)
return ret;
- data->busclk = devm_clk_get(&pdev->dev, "ahb");
+ data->busclk = devm_clk_get(dev, "ahb");
if (IS_ERR(data->busclk)) {
ret = PTR_ERR(data->busclk);
- dev_err(&pdev->dev, "failed to get ahb clk: %d\n", ret);
- return ret;
+ if (ret != -ENOENT) {
+ dev_err(dev, "failed to get ahb clk: %d\n", ret);
+ return ret;
+ }
+
+ data->busclk = NULL;
}
- data->clk = devm_clk_get(&pdev->dev, "ths");
+ data->clk = devm_clk_get(dev, "ths");
if (IS_ERR(data->clk)) {
ret = PTR_ERR(data->clk);
- dev_err(&pdev->dev, "failed to get ths clk: %d\n", ret);
- return ret;
+ if (ret != -ENOENT) {
+ dev_err(dev, "failed to get ths clk: %d\n", ret);
+ return ret;
+ }
+
+ data->clk = NULL;
}
- data->reset = devm_reset_control_get(&pdev->dev, "ahb");
+ data->reset = devm_reset_control_get_optional(dev, "ahb");
if (IS_ERR(data->reset)) {
ret = PTR_ERR(data->reset);
- dev_err(&pdev->dev, "failed to get reset: %d\n", ret);
+ dev_err(dev, "failed to get reset: %d\n", ret);
return ret;
}
ret = reset_control_deassert(data->reset);
if (ret) {
- dev_err(&pdev->dev, "reset deassert failed: %d\n", ret);
+ dev_err(dev, "reset deassert failed: %d\n", ret);
return ret;
}
- ret = clk_prepare_enable(data->busclk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable bus clk: %d\n", ret);
- goto err_assert_reset;
+ if (data->busclk) {
+ ret = clk_prepare_enable(data->busclk);
+ if (ret) {
+ dev_err(dev, "failed to enable bus clk: %d\n", ret);
+ goto err_assert_reset;
+ }
}
- ret = clk_prepare_enable(data->clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable ths clk: %d\n", ret);
- goto err_disable_bus;
- }
+ if (data->clk) {
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable ths clk: %d\n", ret);
+ goto err_disable_bus;
+ }
- ret = clk_set_rate(data->clk, THS_H3_CLK_IN);
- if (ret)
- goto err_disable_ths;
-
- data->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, data,
- &sun8i_ths_thermal_ops);
- if (IS_ERR(data->tzd)) {
- ret = PTR_ERR(data->tzd);
- dev_err(&pdev->dev, "failed to register thermal zone: %d\n",
- ret);
- goto err_disable_ths;
+ ret = clk_set_rate(data->clk, THS_SUN8I_CLK_IN);
+ if (ret)
+ goto err_disable_ths;
}
- sun8i_ths_h3_init(data);
+ for (i = 0; i < data->desc->num_sensors; i++) {
+ data->tzds[i].data = data;
+ data->tzds[i].tzd =
+ devm_thermal_zone_of_sensor_register(dev, i,
+ &data->tzds[i],
+ &sun8i_ths_thermal_ops);
+ if (IS_ERR(data->tzds[i].tzd)) {
+ ret = PTR_ERR(data->tzds[i].tzd);
+ dev_err(dev,
+ "failed to register thermal zone: %d\n", ret);
+ goto err_disable_ths;
+ }
+ }
- platform_set_drvdata(pdev, data);
+ sun8i_ths_init(data);
return 0;
err_disable_ths:
- clk_disable_unprepare(data->clk);
+ if (data->clk)
+ clk_disable_unprepare(data->clk);
err_disable_bus:
- clk_disable_unprepare(data->busclk);
+ if (data->busclk)
+ clk_disable_unprepare(data->busclk);
err_assert_reset:
reset_control_assert(data->reset);
return ret;
@@ -212,13 +342,60 @@ static int sun8i_ths_remove(struct platform_device *pdev)
struct sun8i_ths_data *data = platform_get_drvdata(pdev);
reset_control_assert(data->reset);
- clk_disable_unprepare(data->clk);
- clk_disable_unprepare(data->busclk);
+ if (data->clk)
+ clk_disable_unprepare(data->clk);
+ if (data->busclk)
+ clk_disable_unprepare(data->busclk);
return 0;
}
+struct sun8i_ths_sensor_desc sun8i_ths_h3_sensors[] = {
+ {
+ .data_int_en = THS_SUN8I_INT_CTRL_DATA0_IRQ_EN,
+ .data_int_flag = THS_SUN8I_STAT_DATA0_IRQ_STS,
+ .data_offset = THS_SUN8I_DATA0,
+ .sense_en = THS_SUN8I_CTRL2_SENSE_EN0,
+ },
+};
+
+struct sun8i_ths_sensor_desc sun8i_ths_a83t_sensors[] = {
+ {
+ .data_int_en = THS_SUN8I_INT_CTRL_DATA0_IRQ_EN,
+ .data_int_flag = THS_SUN8I_STAT_DATA0_IRQ_STS,
+ .data_offset = THS_SUN8I_DATA0,
+ .sense_en = THS_SUN8I_CTRL2_SENSE_EN0,
+ },
+ {
+ .data_int_en = THS_SUN8I_INT_CTRL_DATA1_IRQ_EN,
+ .data_int_flag = THS_SUN8I_STAT_DATA1_IRQ_STS,
+ .data_offset = THS_SUN8I_DATA1,
+ .sense_en = THS_SUN8I_CTRL2_SENSE_EN1,
+ },
+ {
+ .data_int_en = THS_SUN8I_INT_CTRL_DATA2_IRQ_EN,
+ .data_int_flag = THS_SUN8I_STAT_DATA2_IRQ_STS,
+ .data_offset = THS_SUN8I_DATA2,
+ .sense_en = THS_SUN8I_CTRL2_SENSE_EN2,
+ },
+};
+
+static const struct sun8i_ths_desc sun8i_ths_h3_desc = {
+ .num_sensors = ARRAY_SIZE(sun8i_ths_h3_sensors),
+ .sensors = sun8i_ths_h3_sensors,
+ .calc_temp = sun8i_ths_calc_temp_h3,
+ .has_cal1 = false,
+};
+
+static const struct sun8i_ths_desc sun8i_ths_a83t_desc = {
+ .num_sensors = ARRAY_SIZE(sun8i_ths_a83t_sensors),
+ .sensors = sun8i_ths_a83t_sensors,
+ .calc_temp = sun8i_ths_calc_temp_a83t,
+ .has_cal1 = true,
+};
+
static const struct of_device_id sun8i_ths_id_table[] = {
- { .compatible = "allwinner,sun8i-h3-ths", },
+ { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_ths_h3_desc },
+ { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_ths_a83t_desc },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, sun8i_ths_id_table);
@@ -235,5 +412,5 @@ static struct platform_driver sun8i_ths_driver = {
module_platform_driver(sun8i_ths_driver);
MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
-MODULE_DESCRIPTION("Thermal sensor driver for Allwinner H3 SoC");
+MODULE_DESCRIPTION("Thermal sensor driver for Allwinner SUN8I SoCs");
MODULE_LICENSE("GPL v2");
--
2.20.1