From b3201b563d36eb799d3f9e14871d5dda2b11f3e8 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 12 Apr 2012 11:05:35 +0200 Subject: staging:iio:adc: Add SPEAr ADC driver This patch implements the basic single data conversion support for the SPEAr600 SoC ADC. The register layout of SPEAr600 differs a bit from other SPEAr SoC variants (e.g. SPEAr3xx). These differences are handled via DT compatible testing. Resulting in a multi-arch binary. This driver is currently tested only on SPEAr600. Future patches may add support for other SoC variants (SPEAr3xx) and features like software buffer or DMA. Signed-off-by: Stefan Roese Acked-by: Jonathan Cameron Acked-by: Viresh Kumar Cc: Greg KH Signed-off-by: Greg Kroah-Hartman --- .../bindings/staging/iio/adc/spear-adc.txt | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt b/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt new file mode 100644 index 000000000000..02ea23a63f20 --- /dev/null +++ b/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt @@ -0,0 +1,26 @@ +* ST SPEAr ADC device driver + +Required properties: +- compatible: Should be "st,spear600-adc" +- reg: Address and length of the register set for the device +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device +- interrupts: Should contain the ADC interrupt +- sampling-frequency: Default sampling frequency + +Optional properties: +- vref-external: External voltage reference in milli-volts. If omitted + the internal voltage reference will be used. +- average-samples: Number of samples to generate an average value. If + omitted, single data conversion will be used. + +Examples: + + adc: adc@d8200000 { + compatible = "st,spear600-adc"; + reg = <0xd8200000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <6>; + sampling-frequency = <5000000>; + vref-external = <2500>; /* 2.5V VRef */ + }; -- cgit v1.2.3 From 1f9e349460389963838aa5428425e7dc31000af6 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sat, 21 Apr 2012 10:10:16 +0200 Subject: iio: Add device tree support to LPC32xx ADC This patch adds device tree support to the LPC32xx's ADC. Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt | 16 ++++++++++++++++ drivers/staging/iio/adc/lpc32xx_adc.c | 10 ++++++++++ 2 files changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt b/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt new file mode 100644 index 000000000000..b3629d3a9adf --- /dev/null +++ b/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt @@ -0,0 +1,16 @@ +* NXP LPC32xx SoC ADC controller + +Required properties: +- compatible: must be "nxp,lpc3220-adc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The ADC interrupt + +Example: + + adc@40048000 { + compatible = "nxp,lpc3220-adc"; + reg = <0x40048000 0x1000>; + interrupt-parent = <&mic>; + interrupts = <39 0>; + }; diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c index ce9320bb9e62..d7f4fe42d17e 100644 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/drivers/staging/iio/adc/lpc32xx_adc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "../iio.h" #include "../sysfs.h" @@ -222,12 +223,21 @@ static int __devexit lpc32xx_adc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id lpc32xx_adc_match[] = { + { .compatible = "nxp,lpc3220-adc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_adc_match); +#endif + static struct platform_driver lpc32xx_adc_driver = { .probe = lpc32xx_adc_probe, .remove = __devexit_p(lpc32xx_adc_remove), .driver = { .name = MOD_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lpc32xx_adc_match), }, }; -- cgit v1.2.3 From e364185f3ed2ecc0a4dbfe2507f20fd5db76c966 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 11 May 2012 15:35:37 +0200 Subject: IIO: AT91: Add DT support to at91_adc driver Signed-off-by: Maxime Ripard Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/arm/atmel-adc.txt | 65 ++++++++++ drivers/iio/adc/at91_adc.c | 132 ++++++++++++++++++++- 2 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/atmel-adc.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt new file mode 100644 index 000000000000..c63097d6afeb --- /dev/null +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt @@ -0,0 +1,65 @@ +* AT91's Analog to Digital Converter (ADC) + +Required properties: + - compatible: Should be "atmel,at91sam9260-adc" + - reg: Should contain ADC registers location and length + - interrupts: Should contain the IRQ line for the ADC + - atmel,adc-channel-base: Offset of the first channel data register + - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this + device + - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC + - atmel,adc-num-channels: Number of channels available in the ADC + - atmel,adc-startup-time: Startup Time of the ADC in microseconds as + defined in the datasheet + - atmel,adc-status-register: Offset of the Interrupt Status Register + - atmel,adc-trigger-register: Offset of the Trigger Register + - atmel,adc-vref: Reference voltage in millivolts for the conversions + +Optional properties: + - atmel,adc-use-external: Boolean to enable of external triggers + +Optional trigger Nodes: + - Required properties: + * trigger-name: Name of the trigger exposed to the user + * trigger-value: Value to put in the Trigger register + to activate this trigger + - Optional properties: + * trigger-external: Is the trigger an external trigger? + +Examples: +adc0: adc@fffb0000 { + compatible = "atmel,at91sam9260-adc"; + reg = <0xfffb0000 0x100>; + interrupts = <20 4>; + atmel,adc-channel-base = <0x30>; + atmel,adc-channels-used = <0xff>; + atmel,adc-drdy-mask = <0x10000>; + atmel,adc-num-channels = <8>; + atmel,adc-startup-time = <40>; + atmel,adc-status-register = <0x1c>; + atmel,adc-trigger-register = <0x08>; + atmel,adc-use-external; + atmel,adc-vref = <3300>; + + trigger@0 { + trigger-name = "external-rising"; + trigger-value = <0x1>; + trigger-external; + }; + trigger@1 { + trigger-name = "external-falling"; + trigger-value = <0x2>; + trigger-external; + }; + + trigger@2 { + trigger-name = "external-any"; + trigger-value = <0x3>; + trigger-external; + }; + + trigger@3 { + trigger-name = "continuous"; + trigger-value = <0x6>; + }; +}; diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index e2eb6139daf7..f18a95d80255 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -415,6 +417,123 @@ static int at91_adc_read_raw(struct iio_dev *idev, return -EINVAL; } +static int at91_adc_probe_dt(struct at91_adc_state *st, + struct platform_device *pdev) +{ + struct iio_dev *idev = iio_priv_to_dev(st); + struct device_node *node = pdev->dev.of_node; + struct device_node *trig_node; + int i = 0, ret; + u32 prop; + + if (!node) + return -EINVAL; + + st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers"); + + if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) { + dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + st->channels_mask = prop; + + if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) { + dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + st->num_channels = prop; + + if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) { + dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + st->startup_time = prop; + + + if (of_property_read_u32(node, "atmel,adc-vref", &prop)) { + dev_err(&idev->dev, "Missing adc-vref property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + st->vref_mv = prop; + + st->registers = devm_kzalloc(&idev->dev, + sizeof(struct at91_adc_reg_desc), + GFP_KERNEL); + if (!st->registers) { + dev_err(&idev->dev, "Could not allocate register memory.\n"); + ret = -ENOMEM; + goto error_ret; + } + + if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) { + dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + st->registers->channel_base = prop; + + if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) { + dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + st->registers->drdy_mask = prop; + + if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) { + dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + st->registers->status_register = prop; + + if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) { + dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + st->registers->trigger_register = prop; + + st->trigger_number = of_get_child_count(node); + st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number * + sizeof(struct at91_adc_trigger), + GFP_KERNEL); + if (!st->trigger_list) { + dev_err(&idev->dev, "Could not allocate trigger list memory.\n"); + ret = -ENOMEM; + goto error_ret; + } + + for_each_child_of_node(node, trig_node) { + struct at91_adc_trigger *trig = st->trigger_list + i; + const char *name; + + if (of_property_read_string(trig_node, "trigger-name", &name)) { + dev_err(&idev->dev, "Missing trigger-name property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + trig->name = name; + + if (of_property_read_u32(trig_node, "trigger-value", &prop)) { + dev_err(&idev->dev, "Missing trigger-value property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + trig->value = prop; + trig->is_external = of_property_read_bool(trig_node, "trigger-external"); + i++; + } + + return 0; + +error_ret: + return ret; +} + static int at91_adc_probe_pdata(struct at91_adc_state *st, struct platform_device *pdev) { @@ -456,7 +575,11 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) st = iio_priv(idev); - ret = at91_adc_probe_pdata(st, pdev); + if (pdev->dev.of_node) + ret = at91_adc_probe_dt(st, pdev); + else + ret = at91_adc_probe_pdata(st, pdev); + if (ret) { dev_err(&pdev->dev, "No platform data available.\n"); ret = -EINVAL; @@ -657,11 +780,18 @@ static int __devexit at91_adc_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id at91_adc_dt_ids[] = { + { .compatible = "atmel,at91sam9260-adc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, at91_adc_dt_ids); + static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, .remove = __devexit_p(at91_adc_remove), .driver = { .name = "at91_adc", + .of_match_table = of_match_ptr(at91_adc_dt_ids), }, }; -- cgit v1.2.3