From 5a07c1d98dd498c01308407c5a3fbd9291f2278a Mon Sep 17 00:00:00 2001
From: Mitko Gamishev <hehopmajieh@debian.bg>
Date: Wed, 5 Feb 2020 14:57:10 +0200
Subject: drv:iio:adc:axp20x_adc arm64:dts:axp803 hwmon enable thermal

---
 arch/arm64/boot/dts/allwinner/axp803.dtsi |  1 +
 drivers/iio/adc/axp20x_adc.c              | 90 +++++++++++++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/axp803.dtsi b/arch/arm64/boot/dts/allwinner/axp803.dtsi
index a6b4b87f185d..422be59f5d88 100644
--- a/arch/arm64/boot/dts/allwinner/axp803.dtsi
+++ b/arch/arm64/boot/dts/allwinner/axp803.dtsi
@@ -19,6 +19,7 @@ ac_power_supply: ac-power {
 	axp_adc: adc {
 		compatible = "x-powers,axp803-adc", "x-powers,axp813-adc";
 		#io-channel-cells = <1>;
+		#thermal-sensor-cells = <0>;
 	};
 
 	axp_gpio: gpio {
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 50eef565df2c..dda093076c1d 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -8,6 +8,7 @@
 #include <linux/unaligned.h>
 #include <linux/bitfield.h>
 #include <linux/completion.h>
+#include <linux/hwmon.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -1005,6 +1006,73 @@ static int axp813_adc_rate(struct axp20x_adc_iio *info, int rate)
 				 AXP813_ADC_RATE_HZ(rate));
 }
 
+static umode_t axp813_adc_hwmon_is_visible(const void *data,
+					   enum hwmon_sensor_types type,
+					   u32 attr, int channel)
+{
+	return (type == hwmon_temp && attr == hwmon_temp_input) ? 0444 : 0;
+}
+
+static int axp813_adc_hwmon_read(struct device *dev,
+				 enum hwmon_sensor_types type,
+				 u32 attr, int channel, long *temp)
+{
+	struct axp20x_adc_iio *info = dev_get_drvdata(dev);
+	int ret;
+	int raw;
+
+	switch (attr) {
+		case hwmon_temp_input:
+		raw = axp20x_read_variable_width(info->regmap, AXP22X_PMIC_TEMP_H, 12);
+		*temp = (raw - 2667) * 100;
+		ret = 0;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static u32 axp813_adc_hwmon_chip_config[] = {
+	HWMON_C_REGISTER_TZ,
+	0
+};
+
+static const struct hwmon_channel_info axp813_adc_hwmon_chip = {
+	.type = hwmon_chip,
+	.config = axp813_adc_hwmon_chip_config,
+};
+
+static u32 axp813_adc_hwmon_temp_config[] = {
+	HWMON_T_INPUT,
+	0
+};
+
+
+static const struct hwmon_channel_info axp813_adc_hwmon_temp = {
+	.type = hwmon_temp,
+	.config = axp813_adc_hwmon_temp_config,
+};
+
+
+static const struct hwmon_channel_info *axp813_adc_hwmon_info[] = {
+	&axp813_adc_hwmon_chip,
+	&axp813_adc_hwmon_temp,
+	NULL
+};
+
+static const struct hwmon_ops axp813_adc_hwmon_hwmon_ops = {
+	.is_visible = axp813_adc_hwmon_is_visible,
+	.read = axp813_adc_hwmon_read,
+};
+
+static const struct hwmon_chip_info axp813_adc_hwmon_chip_info = {
+	.ops = &axp813_adc_hwmon_hwmon_ops,
+	.info = axp813_adc_hwmon_info,
+};
+
 struct axp_data {
 	const struct iio_info		*iio_info;
 	int				num_channels;
@@ -1015,6 +1083,7 @@ struct axp_data {
 	unsigned long			adc_en2_mask;
 	int				(*adc_rate)(struct axp20x_adc_iio *info,
 						    int rate);
+	bool				hwmon_en;
 	const struct iio_map		*maps;
 };
 
@@ -1025,6 +1094,7 @@ static const struct axp_data axp192_data = {
 	.adc_en1_mask = AXP192_ADC_EN1_MASK,
 	.adc_en2_mask = AXP192_ADC_EN2_MASK,
 	.adc_rate = axp20x_adc_rate,
+	.hwmon_en = false,
 	.maps = axp20x_maps,
 };
 
@@ -1037,6 +1107,7 @@ static const struct axp_data axp20x_data = {
 	.adc_en2 = AXP20X_ADC_EN2,
 	.adc_en2_mask = AXP20X_ADC_EN2_MASK,
 	.adc_rate = axp20x_adc_rate,
+	.hwmon_en = false,
 	.maps = axp20x_maps,
 };
 
@@ -1047,6 +1118,7 @@ static const struct axp_data axp22x_data = {
 	.adc_en1 = AXP20X_ADC_EN1,
 	.adc_en1_mask = AXP22X_ADC_EN1_MASK,
 	.adc_rate = axp22x_adc_rate,
+	.hwmon_en = false,
 	.maps = axp22x_maps,
 };
 
@@ -1056,6 +1128,7 @@ static const struct axp_data axp717_data = {
 	.channels = axp717_adc_channels,
 	.adc_en1 = AXP717_ADC_CH_EN_CONTROL,
 	.adc_en1_mask = AXP717_ADC_EN1_MASK,
+	.hwmon_en = false,
 	.maps = axp717_maps,
 };
 
@@ -1066,6 +1139,7 @@ static const struct axp_data axp813_data = {
 	.adc_en1 = AXP20X_ADC_EN1,
 	.adc_en1_mask = AXP22X_ADC_EN1_MASK,
 	.adc_rate = axp813_adc_rate,
+	.hwmon_en = true,
 	.maps = axp22x_maps,
 };
 
@@ -1153,8 +1227,24 @@ static int axp20x_probe(struct platform_device *pdev)
 		goto fail_register;
 	}
 
+	if (info->data->hwmon_en) {
+		/* Register hwmon device */
+		struct device *hwmon_dev;
+
+		hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "axp813_adc",
+								 info, &axp813_adc_hwmon_chip_info, NULL);
+		if (IS_ERR(hwmon_dev)) {
+			ret = PTR_ERR(hwmon_dev);
+			dev_err(&pdev->dev, "unable to register hwmon device %d\n", ret);
+			goto fail_hwmon;
+		}
+	}
+
 	return 0;
 
+fail_hwmon:
+	iio_device_unregister(indio_dev);
+
 fail_register:
 	iio_map_array_unregister(indio_dev);
 
-- 
2.35.3

