[PATCH 2/3] iio:adc:palmas: add DT support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




From: Marek Belisko <marek@xxxxxxxxxxxxx>

Code was found at:
https://android.googlesource.com/kernel/tegra/+/a90856a6626d502d42c6e7abccbdf9d730b36270%5E%21/#F1

Signed-off-by: Laxman Dewangan <ldewangan@xxxxxxxxxx>
[Fixed minor typos + add channels list to documentation]
Signed-off-by: Marek Belisko <marek@xxxxxxxxxxxxx>
---
.../devicetree/bindings/iio/adc/palmas-gpadc.txt   |  67 +++++++++++
drivers/iio/adc/palmas_gpadc.c                     | 130 +++++++++++++++++----
2 files changed, 175 insertions(+), 22 deletions(-)
create mode 100644 Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt

diff --git a/Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt b/Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt
new file mode 100644
index 0000000..a5a33ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt
@@ -0,0 +1,67 @@
+* Palmas general purpose ADC IP block devicetree bindings
+
+Channels list:
+	0 battery type
+        1 battery temp NTC
+	2 GP
+	3 temp (with ext. diode)
+	4 GP
+	5 GP
+	6 VBAT_SENSE
+	7 VCC_SENSE
+	8 Backup Battery voltage
+	9 external charger (VCHG)
+	10 VBUS
+	11 DC-DC current probe (how does this work?)
+	12 internal die temp
+	13 internal die temp
+	14 USB ID pin voltage
+	15 test network
+
+Required properties:
+- compatible : Must be "ti,palmas-gpadc".
+
+Optional sub-nodes:
+ti,channel0-current-microamp: Channel 0 current in uA.
+	Valid values 0uA, 5uA, 15uA, 20uA.
+ti,channel3-current-microamp: Channel 3 current in uA.
+	Valid value 0uA, 10uA, 400uA, 800uA.
+ti,enable-channel3-dual-current: Enable dual current on channel 3.
+ti,enable-extended-delay: Enable extended delay.
+
+Optional sub-node:
+The Palmas ADC node has optional subnode to define the iio mapping.
+It is the name with "iio_map". This node has again subnode to define
+the property of the channel. The sub subnode has following properties:
+- ti,adc-channel-number: ADC channel number.
+- ti,adc-consumer-device: Consumer device name.
+- ti,adc-consumer-channel: ADC consumer channel name.
+
+Example:
+
+pmic {
+	compatible = "ti,twl6035-pmic", "ti,palmas-pmic";
+	...
+	gpadc {
+		compatible = "ti,palmas-gpadc";
+		interrupts = <18 0
+			      16 0
+			      17 0>;
+		ti,channel0-current-microamp = <5>;
+		ti,channel3-current-microamp = <10>;
+		iio_map {
+			ch1 {
+				ti,adc-channel-number = <1>;
+				ti,adc-consumer-device = "generic-adc-thermal.0";
+				ti,adc-consumer-channel ="battery-temp-channel";
+			};
+
+			ch6 {
+				ti,adc-channel-number = <6>;
+				ti,adc-consumer-device = "palmas-battery";
+				ti,adc-consumer-channel ="vbat_channel";
+			};
+		};
+	};
+	...
+};
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
index 17abb28..bc4db43 100644
--- a/drivers/iio/adc/palmas_gpadc.c
+++ b/drivers/iio/adc/palmas_gpadc.c
@@ -20,6 +20,8 @@
#include <linux/pm.h>
#include <linux/mfd/palmas.h>
#include <linux/completion.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
@@ -434,20 +436,97 @@ static const struct iio_chan_spec palmas_gpadc_iio_channel[] = {
	PALMAS_ADC_CHAN_IIO(IN15, IIO_VOLTAGE),
};

+static int palmas_gpadc_get_adc_dt_data(struct platform_device *pdev,
+	struct palmas_gpadc_platform_data **gpadc_pdata)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct palmas_gpadc_platform_data *gp_data;
+	struct device_node *map_node;
+	struct device_node *child;
+	struct iio_map *palmas_iio_map;
+	int ret;
+	u32 pval;
+	int nmap, nvalid_map;
+
+	gp_data = devm_kzalloc(&pdev->dev, sizeof(*gp_data), GFP_KERNEL);
+	if (!gp_data)
+		return -ENOMEM;
+
+	ret = of_property_read_u32(np, "ti,channel0-current-microamp", &pval);
+	if (!ret)
+		gp_data->ch0_current = pval;
+
+	ret = of_property_read_u32(np, "ti,channel3-current-microamp", &pval);
+	if (!ret)
+		gp_data->ch3_current = pval;
+
+	gp_data->extended_delay = of_property_read_bool(np,
+					"ti,enable-extended-delay");
+
+	map_node = of_get_child_by_name(np, "iio_map");
+	if (!map_node) {
+		dev_warn(&pdev->dev, "IIO map table not found\n");
+		goto done;
+	}
+
+	nmap = of_get_child_count(map_node);
+	if (!nmap)
+		goto done;
+
+	nmap++;
+	palmas_iio_map = devm_kzalloc(&pdev->dev,
+				sizeof(*palmas_iio_map) * nmap, GFP_KERNEL);
+	if (!palmas_iio_map)
+		goto done;
+
+	nvalid_map = 0;
+	for_each_child_of_node(map_node, child) {
+		ret = of_property_read_u32(child, "ti,adc-channel-number",
+					&pval);
+		if (!ret && pval < ARRAY_SIZE(palmas_gpadc_iio_channel))
+			palmas_iio_map[nvalid_map].adc_channel_label =
+				palmas_gpadc_iio_channel[pval].datasheet_name;
+		of_property_read_string(child, "ti,adc-consumer-device",
+				&palmas_iio_map[nvalid_map].consumer_dev_name);
+		of_property_read_string(child, "ti,adc-consumer-channel",
+				&palmas_iio_map[nvalid_map].consumer_channel);
+		dev_dbg(&pdev->dev,
+			"Channel %s consumer dev %s and consumer channel %s\n",
+				palmas_iio_map[nvalid_map].adc_channel_label,
+				palmas_iio_map[nvalid_map].consumer_dev_name,
+				palmas_iio_map[nvalid_map].consumer_channel);
+		nvalid_map++;
+	}
+	palmas_iio_map[nvalid_map].adc_channel_label = NULL;
+	palmas_iio_map[nvalid_map].consumer_dev_name = NULL;
+	palmas_iio_map[nvalid_map].consumer_channel = NULL;
+
+	gp_data->iio_maps = palmas_iio_map;
+
+done:
+	*gpadc_pdata = gp_data;
+	return 0;
+}
+
static int palmas_gpadc_probe(struct platform_device *pdev)
{
	struct palmas_gpadc *adc;
	struct palmas_platform_data *pdata;
-	struct palmas_gpadc_platform_data *adc_pdata;
+	struct palmas_gpadc_platform_data *gpadc_pdata = NULL;
	struct iio_dev *iodev;
	int ret, i;

	pdata = dev_get_platdata(pdev->dev.parent);
-	if (!pdata || !pdata->gpadc_pdata) {
-		dev_err(&pdev->dev, "No platform data\n");
-		return -ENODEV;
+	if (pdata && pdata->gpadc_pdata)
+		gpadc_pdata = pdata->gpadc_pdata;
+
+	if (!gpadc_pdata && pdev->dev.of_node) {
+		ret = palmas_gpadc_get_adc_dt_data(pdev, &gpadc_pdata);
+		if (ret < 0)
+			return ret;
	}
-	adc_pdata = pdata->gpadc_pdata;
+	if (!gpadc_pdata)
+		return -EINVAL;

	iodev = iio_device_alloc(sizeof(*adc));
	if (!iodev) {
@@ -455,8 +534,8 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
		return -ENOMEM;
	}

-	if (adc_pdata->iio_maps) {
-		ret = iio_map_array_register(iodev, adc_pdata->iio_maps);
+	if (gpadc_pdata->iio_maps) {
+		ret = iio_map_array_register(iodev, gpadc_pdata->iio_maps);
		if (ret < 0) {
			dev_err(&pdev->dev, "iio_map_array_register failed\n");
			goto out;
@@ -470,7 +549,7 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
	init_completion(&adc->conv_completion);
	dev_set_drvdata(&pdev->dev, iodev);

-	adc->auto_conversion_period = adc_pdata->auto_conversion_period_ms;
+	adc->auto_conversion_period = gpadc_pdata->auto_conversion_period_ms;
	adc->irq = palmas_irq_get_virq(adc->palmas, PALMAS_GPADC_EOC_SW_IRQ);
	ret = request_threaded_irq(adc->irq, NULL,
		palmas_gpadc_irq,
@@ -482,8 +561,8 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
		goto out_unregister_map;
	}

-	if (adc_pdata->adc_wakeup1_data) {
-		memcpy(&adc->wakeup1_data, adc_pdata->adc_wakeup1_data,
+	if (gpadc_pdata->adc_wakeup1_data) {
+		memcpy(&adc->wakeup1_data, gpadc_pdata->adc_wakeup1_data,
			sizeof(adc->wakeup1_data));
		adc->wakeup1_enable = true;
		adc->irq_auto_0 =  platform_get_irq(pdev, 1);
@@ -498,8 +577,8 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
		}
	}

-	if (adc_pdata->adc_wakeup2_data) {
-		memcpy(&adc->wakeup2_data, adc_pdata->adc_wakeup2_data,
+	if (gpadc_pdata->adc_wakeup2_data) {
+		memcpy(&adc->wakeup2_data, gpadc_pdata->adc_wakeup2_data,
				sizeof(adc->wakeup2_data));
		adc->wakeup2_enable = true;
		adc->irq_auto_1 =  platform_get_irq(pdev, 2);
@@ -514,25 +593,25 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
		}
	}

-	if (adc_pdata->ch0_current == 0)
+	if (gpadc_pdata->ch0_current == 0)
		adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_0;
-	else if (adc_pdata->ch0_current <= 5)
+	else if (gpadc_pdata->ch0_current <= 5)
		adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_5;
-	else if (adc_pdata->ch0_current <= 15)
+	else if (gpadc_pdata->ch0_current <= 15)
		adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_15;
	else
		adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_20;

-	if (adc_pdata->ch3_current == 0)
+	if (gpadc_pdata->ch3_current == 0)
		adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_0;
-	else if (adc_pdata->ch3_current <= 10)
+	else if (gpadc_pdata->ch3_current <= 10)
		adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_10;
-	else if (adc_pdata->ch3_current <= 400)
+	else if (gpadc_pdata->ch3_current <= 400)
		adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_400;
	else
		adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_800;

-	adc->extended_delay = adc_pdata->extended_delay;
+	adc->extended_delay = gpadc_pdata->extended_delay;

	iodev->name = MOD_NAME;
	iodev->dev.parent = &pdev->dev;
@@ -559,15 +638,15 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
	return 0;

out_irq_auto1_free:
-	if (adc_pdata->adc_wakeup2_data)
+	if (gpadc_pdata->adc_wakeup2_data)
		free_irq(adc->irq_auto_1, adc);
out_irq_auto0_free:
-	if (adc_pdata->adc_wakeup1_data)
+	if (gpadc_pdata->adc_wakeup1_data)
		free_irq(adc->irq_auto_0, adc);
out_irq_free:
	free_irq(adc->irq, adc);
out_unregister_map:
-	if (adc_pdata->iio_maps)
+	if (gpadc_pdata->iio_maps)
		iio_map_array_unregister(iodev);
out:
	iio_device_free(iodev);
@@ -769,6 +848,12 @@ static const struct dev_pm_ops palmas_pm_ops = {
				palmas_gpadc_resume)
};

+static const struct of_device_id of_palmas_gpadc_match_tbl[] = {
+	{ .compatible = "ti,palmas-gpadc", },
+	{ /* end */ }
+};
+MODULE_DEVICE_TABLE(of, of_palmas_gpadc_match_tbl);
+
static struct platform_driver palmas_gpadc_driver = {
	.probe = palmas_gpadc_probe,
	.remove = palmas_gpadc_remove,
@@ -776,6 +861,7 @@ static struct platform_driver palmas_gpadc_driver = {
		.name = MOD_NAME,
		.owner = THIS_MODULE,
		.pm = &palmas_pm_ops,
+		.of_match_table = of_palmas_gpadc_match_tbl,
	},
};

-- 
2.5.1


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux