mxs-lradc: Split driver into MFD
Subsystems (5)
v4 cover mxs-lradc: Split driver into MFD
Split existing driver mxs-lradc into MFD with touchscreen and IIO part.
Tested on I.MX28.
Ksenija Stanojevic (4):
mfd: mxs-lradc: Add support for mxs-lradc MFD
iio: adc: mxs-lradc: Add support for adc driver
input: touchscreen: mxs-lradc: Add support for touchscreen
iio: adc: mxs-lradc: Remove driver
drivers/iio/adc/Kconfig | 27 +- drivers/iio/adc/Makefile | 2 +- drivers/iio/adc/mxs-lradc-adc.c | 833 ++++++++++++++ drivers/iio/adc/mxs-lradc.c | 1775 ------------------------------ drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/mxs-lradc-ts.c | 736 +++++++++++++ drivers/mfd/Kconfig | 17 + drivers/mfd/Makefile | 1 + drivers/mfd/mxs-lradc.c | 259 +++++ include/linux/mfd/mxs-lradc.h | 198 ++++ 11 files changed, 2069 insertions(+), 1790 deletions(-) create mode 100644 drivers/iio/adc/mxs-lradc-adc.c delete mode 100644 drivers/iio/adc/mxs-lradc.c create mode 100644 drivers/input/touchscreen/mxs-lradc-ts.c create mode 100644 drivers/mfd/mxs-lradc.c create mode 100644 include/linux/mfd/mxs-lradc.h
Signature · 1 line
1.9.1
PATCH v4 1/4 mfd: mxs-lradc: Add support for mxs-lradc MFD
Add core files for mxs-lradc MFD driver.
Note: this patch won't compile in iio/testing without this patch:a8f447be8056 ("mfd: Add resource managed APIs for mfd_add_devices")
---
Changes in v4:
- update copyright
- use DEFINE_RES_IRQ_NAMED
- remove mxs_lradc_add_device function
- use struct mfd_cell in static form
- improve spacing
- remove unnecessary comment
- remove platform_get_irq
- remove touch_ret and use ret instead
- rename use_touchscreen to touchscreen_wire
- use goto statements
- remove irq[13], irq_count and irq_name from struct mxs_lradc
- remove all defines from inside the struct definition
Changes in v3:
- add note to commit message
- move switch statement into if(touch_ret == 0) branch
- add MODULE_AUTHOR
Changes in v2:
- do not change spacing in Kconfig
- make struct mfd_cell part of struct mxs_lradc
- use switch instead of if in mxs_lradc_irq_mask
- use only necessary header files in mxs_lradc.h
- use devm_mfd_add_device
- use separate function to register mfd device
- change licence to GPL
- add copyright
drivers/mfd/Kconfig | 17 +++ drivers/mfd/Makefile | 1 + drivers/mfd/mxs-lradc.c | 259 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/mxs-lradc.h | 198 ++++++++++++++++++++++++++++++++ 4 files changed, 475 insertions(+) create mode 100644 drivers/mfd/mxs-lradc.c create mode 100644 include/linux/mfd/mxs-lradc.h
drivers/mfd/Kconfig +17 -0
@@ -271,6 +271,23 @@ config MFD_MC13XXX_I2C help Select this if your MC13xxx is connected via an I2C bus. +config MFD_MXS_LRADC + tristate "Freescale i.MX23/i.MX28 LRADC" + depends on ARCH_MXS || COMPILE_TEST + select MFD_CORE + select STMP_DEVICE + help + Say yes here to build support for the Low Resolution + Analog-to-Digital Converter (LRADC) found on the i.MX23 and i.MX28 + processors. This driver provides common support for accessing the + device, additional drivers must be enabled in order to use the + functionality of the device: + mxs-lradc-adc for ADC readings + mxs-lradc-ts for touchscreen support + + This driver can also be built as a module. If so, the module will be + called mxs-lradc. + config MFD_HI6421_PMIC tristate "HiSilicon Hi6421 PMU/Codec IC" depends on OF
drivers/mfd/Makefile +1 -0
@@ -198,3 +198,4 @@ intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o obj-$(CONFIG_MFD_MT6397) += mt6397-core.o +obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
drivers/mfd/mxs-lradc.c new file +259 -0
259 lines not on this page · raw message
include/linux/mfd/mxs-lradc.h new file +198 -0
198 lines not on this page · raw message
Signature · 1 line
1.9.1
Re: [PATCH v4 1/4] mfd: mxs-lradc: Add support for mxs-lradc MFD
Quoted 18 lines · Ksenija Stanojevic
Add core files for mxs-lradc MFD driver.
Note: this patch won't compile in iio/testing without this patch:
a8f447be8056("mfd: Add resource managed APIs formfd_add_devices")Signed-off-by Ksenija Stanojevic <[email protected]>---
[...]drivers/mfd/mxs-lradc.c new file +10
-0+static int mxs_lradc_probe (struct platform_device *pdev) +{ +const struct of_device_id *of_id; +struct device *dev = &pdev->dev; +struct device_node *node = dev->of_node; +struct mxs_lradc *lradc; +struct resource *iores; +struct mfd_cell *cells =NULL ; +int ret =0 ; +u32 ts_wires =0 ;
drivers/mfd/mxs-lradc.c line 145
Quoted 10 lines
drivers/mfd/mxs-lradc.c new file +10
-0+ + lradc =devm_kzalloc (&pdev->dev,sizeof (*lradc),GFP_KERNEL ); +if (!lradc) +return -ENOMEM ; + + of_id =of_match_device (mxs_lradc_dt_ids, &pdev->dev); + lradc->soc = (enum mxs_lradc_id )of_id->data; + + iores =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + lradc->base =devm_ioremap_resource (dev, iores);
Out of couriosity: Is it common to pass already ioremapped addresses to (MFD cell) platform drivers? I would have expected, and done myself, that ioremap is done in the driver itself, same as the IRQ.
Best regards,
Alexander
Re: [PATCH v4 1/4] mfd: mxs-lradc: Add support for mxs-lradc MFD
Quoted 25 lines · Alexander Stein
Quoted 24 lines · Ksenija Stanojevic
Add core files for mxs-lradc MFD driver.
Note: this patch won't compile in iio/testing without this patch:
a8f447be8056("mfd: Add resource managed APIs formfd_add_devices")Signed-off-by Ksenija Stanojevic <[email protected]>---
[...]drivers/mfd/mxs-lradc.c new file +16
-0+static int mxs_lradc_probe (struct platform_device *pdev) +{ +const struct of_device_id *of_id; +struct device *dev = &pdev->dev; +struct device_node *node = dev->of_node; +struct mxs_lradc *lradc; +struct resource *iores; +struct mfd_cell *cells =NULL ; +int ret =0 ; +u32 ts_wires =0 ; + + lradc =devm_kzalloc (&pdev->dev,sizeof (*lradc),GFP_KERNEL ); +if (!lradc) +return -ENOMEM ; + + of_id =of_match_device (mxs_lradc_dt_ids, &pdev->dev);
Quoted 8 lines
drivers/mfd/mxs-lradc.c line 145
Quoted 4 lines
drivers/mfd/mxs-lradc.c new file +4
-0+ lradc->soc = (enum mxs_lradc_id )of_id->data; + + iores =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + lradc->base =devm_ioremap_resource (dev, iores);Out of couriosity: Is it common to pass already ioremapped addresses to (MFD cell) platform drivers? I would have expected, and done myself, that ioremap is done in the driver itself, same as the IRQ.
Yes, this is exactly what should happen.
Signature · 4 lines
Lee Jones Linaro STMicroelectronics Landing Team Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
Jonathan Cameron
maintainerRe: [PATCH v4 1/4] mfd: mxs-lradc: Add support for mxs-lradc MFD
Quoted 36 lines · Lee Jones
Quoted 25 lines · Alexander Stein
Quoted 24 lines · Ksenija Stanojevic
Add core files for mxs-lradc MFD driver.
Note: this patch won't compile in iio/testing without this patch:
a8f447be8056("mfd: Add resource managed APIs formfd_add_devices")Signed-off-by Ksenija Stanojevic <[email protected]>---
[...]drivers/mfd/mxs-lradc.c new file +16
-0+static int mxs_lradc_probe (struct platform_device *pdev) +{ +const struct of_device_id *of_id; +struct device *dev = &pdev->dev; +struct device_node *node = dev->of_node; +struct mxs_lradc *lradc; +struct resource *iores; +struct mfd_cell *cells =NULL ; +int ret =0 ; +u32 ts_wires =0 ; + + lradc =devm_kzalloc (&pdev->dev,sizeof (*lradc),GFP_KERNEL ); +if (!lradc) +return -ENOMEM ; + + of_id =of_match_device (mxs_lradc_dt_ids, &pdev->dev);Quoted 8 lines
drivers/mfd/mxs-lradc.c line 145
Quoted 4 lines
drivers/mfd/mxs-lradc.c new file +4
-0+ lradc->soc = (enum mxs_lradc_id )of_id->data; + + iores =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + lradc->base =devm_ioremap_resource (dev, iores);Out of couriosity: Is it common to pass already ioremapped addresses to (MFD cell) platform drivers? I would have expected, and done myself, that ioremap is done in the driver itself, same as the IRQ.
Quoted 2 lines
Yes, this is exactly what should happen.
Lee, you've confused me with this answer. Yes, it is common or Yes it should have been done the way Alexander suggested?
Jonathan
Re: [PATCH v4 1/4] mfd: mxs-lradc: Add support for mxs-lradc MFD
Quoted 37 lines · Jonathan Cameron
Quoted 36 lines · Lee Jones
Quoted 33 lines · Alexander Stein
Quoted 18 lines · Ksenija Stanojevic
Add core files for mxs-lradc MFD driver.
Note: this patch won't compile in iio/testing without this patch:
a8f447be8056("mfd: Add resource managed APIs formfd_add_devices")Signed-off-by Ksenija Stanojevic <[email protected]>---
[...]drivers/mfd/mxs-lradc.c new file +10
-0+static int mxs_lradc_probe (struct platform_device *pdev) +{ +const struct of_device_id *of_id; +struct device *dev = &pdev->dev; +struct device_node *node = dev->of_node; +struct mxs_lradc *lradc; +struct resource *iores; +struct mfd_cell *cells =NULL ; +int ret =0 ; +u32 ts_wires =0 ;drivers/mfd/mxs-lradc.c line 145
Quoted 10 lines
drivers/mfd/mxs-lradc.c new file +10
-0+ + lradc =devm_kzalloc (&pdev->dev,sizeof (*lradc),GFP_KERNEL ); +if (!lradc) +return -ENOMEM ; + + of_id =of_match_device (mxs_lradc_dt_ids, &pdev->dev); + lradc->soc = (enum mxs_lradc_id )of_id->data; + + iores =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + lradc->base =devm_ioremap_resource (dev, iores);Out of couriosity: Is it common to pass already ioremapped addresses to (MFD cell) platform drivers? I would have expected, and done myself, that ioremap is done in the driver itself, same as the IRQ.
Quoted 4 lines
Quoted 2 lines
Yes, this is exactly what should happen.
Lee, you've confused me with this answer. Yes, it is common or Yes it should have been done the way Alexander suggested?
The remapping and IRQ obtainment should be done in the leaf driver.
Signature · 4 lines
Lee Jones Linaro STMicroelectronics Landing Team Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
PATCH v4 2/4 iio: adc: mxs-lradc: Add support for adc driver
In reply to Ksenija StanojevicAdd support for sixteen-channel 12-bit resolution ADC and its functions, which include general-purpose ADC readings, battery voltage measurement, and die temperature measurement.
---
Changes in v4:
- update copyright
- use platform_get_irq_byname
- use irq_of_parse_and_map
Changes in v3:
- nothing
Changes in v2:
- improve commit message
- do not change spacing in Kconfig
- impove formating
- remove wrapper show_scale_avail
- use correct syntax for comments
- use devm_iio_trigger_alloc
- do not allocate buffer dynamically
- use iio_device_claim_*_mode helpers
- add spinlock in struct mxs_lradc_ts to enable locking in interrupt handler
- only grab irqs that are relevant to adc
- remove blank line at the end of the file
- change licence to GPL
- add copyright
drivers/iio/adc/Kconfig | 13 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mxs-lradc-adc.c | 833 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 847 insertions(+) create mode 100644 drivers/iio/adc/mxs-lradc-adc.c
drivers/iio/adc/Kconfig +13 -0
@@ -194,6 +194,19 @@ config EXYNOS_ADC To compile this driver as a module, choose M here: the module will be called exynos_adc. +config MXS_LRADC_ADC + tristate "Freescale i.MX23/i.MX28 LRADC ADC" + depends on MFD_MXS_LRADC + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the ADC functions of the + i.MX23/i.MX28 LRADC. This includes general-purpose ADC readings, + battery voltage measurement, and die temperature measurement. + + This driver can also be built as a module. If so, the module will be + called mxs-lradc-adc. + config HI8435 tristate "Holt Integrated Circuits HI-8435 threshold detector" select IIO_TRIGGERED_EVENT
drivers/iio/adc/Makefile +1 -0
@@ -29,6 +29,7 @@ obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o +obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
drivers/iio/adc/mxs-lradc-adc.c new file +833 -0
833 lines not on this page · raw message
Signature · 1 line
1.9.1
Re: [PATCH v4 2/4] iio: adc: mxs-lradc: Add support for adc driver
Quoted 5 lines · Ksenija Stanojevic
Add support for sixteen-channel 12-bit resolution ADC and its functions, which include general-purpose ADC readings, battery voltage measurement, and die temperature measurement.
Signed-off-by Ksenija Stanojevic <[email protected]>
Quoted 906 lines
---
Changes in v4:
- update copyright
- useplatform_get_irq_byname
- useirq_of_parse_and_mapChanges in v3:
- nothingChanges in v2:
- improve commit message
- do not change spacing inKconfig
- impove formating
- remove wrappershow_scale_avail
- use correct syntax for comments
- usedevm_iio_trigger_alloc
- do not allocate buffer dynamically
- use iio_device_claim_*_mode helpers
- add spinlock in structmxs_lradc_tsto enable locking in interrupt handler
- only grab irqs that are relevant to adc
- remove blank line at the end of the file
- change licence to GPL
- add copyrightdrivers/iio/adc/Kconfig | 13 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mxs-lradc-adc.c | 833 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 847 insertions(+) create mode 100644 drivers/iio/adc/mxs-lradc-adc.cdrivers/iio/adc/Kconfig +13
-0@@ -194,6 +194,19 @@ config EXYNOS_ADC To compile this driver as a module, choose M here: the module will be called exynos_adc. +config MXS_LRADC_ADC + tristate "Freescale i.MX23/i.MX28 LRADC ADC" + depends on MFD_MXS_LRADC + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the ADC functions of the + i.MX23/i.MX28 LRADC. This includes general-purpose ADC readings, + battery voltage measurement, and die temperature measurement. + + This driver can also be built as a module. If so, the module will be + called mxs-lradc-adc. + config HI8435 tristate "Holt Integrated Circuits HI-8435 threshold detector" select IIO_TRIGGERED_EVENTdrivers/iio/adc/Makefile +1
-0@@ -29,6 +29,7 @@ obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o +obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.odrivers/iio/adc/mxs-lradc-adc.c new file +833
-0@@ -0,0 +1,833 @@ +/* +* Freescale MXS LRADC ADC driver +* +* Copyright (c) 2012 DENX Software Engineering, GmbH. +* +* Authors: +* Marek Vasut <[email protected]> +* Ksenija Stanojevic <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/mfd/core.h> +#include <linux/mfd/mxs-lradc.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/sysfs.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/sysfs.h> + +/* +* Make this runtime configurable if necessary. Currently, if the buffered mode +* is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before +* triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000) +* seconds. The result is that the samples arrive every 500mS. +*/ +#define LRADC_DELAY_TIMER_PER 200 +#define LRADC_DELAY_TIMER_LOOP 5 + +#define VREF_MV_BASE 1850 + +const char *mx23_lradc_adc_irq_names[] = { +"mxs-lradc-channel0" , +"mxs-lradc-channel1" , +"mxs-lradc-channel2" , +"mxs-lradc-channel3" , +"mxs-lradc-channel4" , +"mxs-lradc-channel5" , +}; + +const char *mx28_lradc_adc_irq_names[] = { +"mxs-lradc-thresh0" , +"mxs-lradc-thresh1" , +"mxs-lradc-channel0" , +"mxs-lradc-channel1" , +"mxs-lradc-channel2" , +"mxs-lradc-channel3" , +"mxs-lradc-channel4" , +"mxs-lradc-channel5" , +"mxs-lradc-button0" , +"mxs-lradc-button1" , +}; + +static const u32 mxs_lradc_adc_vref_mv[][LRADC_MAX_TOTAL_CHANS ] = { + [IMX23_LRADC ] = { +VREF_MV_BASE ,/* CH0 */ +VREF_MV_BASE ,/* CH1 */ +VREF_MV_BASE ,/* CH2 */ +VREF_MV_BASE ,/* CH3 */ +VREF_MV_BASE ,/* CH4 */ +VREF_MV_BASE ,/* CH5 */ +VREF_MV_BASE *2 ,/* CH6 VDDIO */ +VREF_MV_BASE *4 ,/* CH7 VBATT */ +VREF_MV_BASE ,/* CH8 Temp sense 0 */ +VREF_MV_BASE ,/* CH9 Temp sense 1 */ +VREF_MV_BASE ,/* CH10 */ +VREF_MV_BASE ,/* CH11 */ +VREF_MV_BASE ,/* CH12 USB_DP */ +VREF_MV_BASE ,/* CH13 USB_DN */ +VREF_MV_BASE ,/* CH14 VBG */ +VREF_MV_BASE *4 ,/* CH15 VDD5V */ + }, + [IMX28_LRADC ] = { +VREF_MV_BASE ,/* CH0 */ +VREF_MV_BASE ,/* CH1 */ +VREF_MV_BASE ,/* CH2 */ +VREF_MV_BASE ,/* CH3 */ +VREF_MV_BASE ,/* CH4 */ +VREF_MV_BASE ,/* CH5 */ +VREF_MV_BASE ,/* CH6 */ +VREF_MV_BASE *4 ,/* CH7 VBATT */ +VREF_MV_BASE ,/* CH8 Temp sense 0 */ +VREF_MV_BASE ,/* CH9 Temp sense 1 */ +VREF_MV_BASE *2 ,/* CH10 VDDIO */ +VREF_MV_BASE ,/* CH11 VTH */ +VREF_MV_BASE *2 ,/* CH12 VDDA */ +VREF_MV_BASE ,/* CH13 VDDD */ +VREF_MV_BASE ,/* CH14 VBG */ +VREF_MV_BASE *4 ,/* CH15 VDD5V */ + }, +}; + +enum mxs_lradc_divbytwo { +MXS_LRADC_DIV_DISABLED =0 , +MXS_LRADC_DIV_ENABLED , +}; + +struct mxs_lradc_scale { +unsigned int integer; +unsigned int nano; +}; + +struct mxs_lradc_adc { +struct mxs_lradc *lradc; +struct device *dev; + +u32 buffer[10 ]; +struct iio_trigger *trig; +struct completion completion; +spinlock_t lock; + +const u32 *vref_mv; +struct mxs_lradc_scale scale_avail[LRADC_MAX_TOTAL_CHANS ][2 ]; +unsigned long is_divided; +}; + + +/* Raw I/O operations */ +static int mxs_lradc_adc_read_single (struct iio_dev *iio_dev,int chan, +int *val) +{ +struct mxs_lradc_adc *adc =iio_priv (iio_dev); +struct mxs_lradc *lradc = adc->lradc; +int ret; + +/* +* See if there is no buffered operation in progress. If there is simply +* bail out. This can be improved to support both buffered and raw IO at +* the same time, yet the code becomes horribly complicated. Therefore I +* applied KISS principle here. +*/ + ret =iio_device_claim_direct_mode (iio_dev); +if (ret) +return ret; + +reinit_completion (&adc->completion); + +/* +* No buffered operation in progress, map the channel and trigger it. +* Virtual channel 0 is always used here as the others are always not +* used if doing raw sampling. +*/ +if (lradc->soc ==IMX28_LRADC ) +mxs_lradc_reg_clear (lradc,LRADC_CTRL1_LRADC_IRQ_EN (0 ), +LRADC_CTRL1 ); +mxs_lradc_reg_clear (lradc,0x1 ,LRADC_CTRL0 ); + +/* Enable / disable the divider per requirement */ +if (test_bit (chan, &adc->is_divided)) +mxs_lradc_reg_set (lradc, +1 <<LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET , +LRADC_CTRL2 ); +else +mxs_lradc_reg_clear (lradc, +1 <<LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET , +LRADC_CTRL2 ); + +/* Clean the slot's previous content, then set new one. */ +mxs_lradc_reg_clear (lradc,LRADC_CTRL4_LRADCSELECT_MASK (0 ), +LRADC_CTRL4 ); +mxs_lradc_reg_set (lradc, chan,LRADC_CTRL4 ); + +mxs_lradc_reg_wrt (lradc,0 ,LRADC_CH (0 )); + +/* Enable the IRQ and start sampling the channel. */ +mxs_lradc_reg_set (lradc,LRADC_CTRL1_LRADC_IRQ_EN (0 ),LRADC_CTRL1 ); +mxs_lradc_reg_set (lradc,BIT (0 ),LRADC_CTRL0 ); + +/* Wait for completion on the channel, 1 second max. */ + ret =wait_for_completion_killable_timeout (&adc->completion,HZ ); +if (!ret) + ret = -ETIMEDOUT ; +if (ret <0 ) + goto err; + +/* Read the data. */ + *val =readl (lradc->base +LRADC_CH (0 )) &LRADC_CH_VALUE_MASK ; + ret =IIO_VAL_INT ; + +err: +mxs_lradc_reg_clear (lradc,LRADC_CTRL1_LRADC_IRQ_EN (0 ),LRADC_CTRL1 ); + +iio_device_release_direct_mode (iio_dev); + +return ret; +} + +static int mxs_lradc_adc_read_temp (struct iio_dev *iio_dev,int *val) +{ +int ret, min, max; + + ret =mxs_lradc_adc_read_single (iio_dev,8 , &min); +if (ret !=IIO_VAL_INT ) +return ret; + + ret =mxs_lradc_adc_read_single (iio_dev,9 , &max); +if (ret !=IIO_VAL_INT ) +return ret; + + *val = max - min; + +return IIO_VAL_INT ; +} + +static int mxs_lradc_adc_read_raw (struct iio_dev *iio_dev, +const struct iio_chan_spec *chan, +int *val,int *val2,long m) +{ +struct mxs_lradc_adc *adc =iio_priv (iio_dev); + +switch (m) { +case IIO_CHAN_INFO_RAW : +if (chan->type ==IIO_TEMP ) +return mxs_lradc_adc_read_temp (iio_dev, val); + +return mxs_lradc_adc_read_single (iio_dev, chan->channel, val); + +case IIO_CHAN_INFO_SCALE : +if (chan->type ==IIO_TEMP ) { +/* +* From the datasheet, we have to multiply by 1.012 and +* divide by 4 +*/ + *val =0 ; + *val2 =253000 ; +return IIO_VAL_INT_PLUS_MICRO ; + } + + *val = adc->vref_mv[chan->channel]; + *val2 = chan->scan_type.realbits - +test_bit (chan->channel, &adc->is_divided); +return IIO_VAL_FRACTIONAL_LOG2 ; + +case IIO_CHAN_INFO_OFFSET : +if (chan->type ==IIO_TEMP ) { +/* +* The calculated value from the ADC is in Kelvin, we +* want Celsius for hwmon so the offset is -273.15 +* The offset is applied before scaling so it is +* actually -213.15 * 4 / 1.012 = -1079.644268 +*/ + *val =-1079 ; + *val2 =644268 ; + +return IIO_VAL_INT_PLUS_MICRO ; + } + +return -EINVAL ; + +default : +break ; + } + +return -EINVAL ; +} + +static int mxs_lradc_adc_write_raw (struct iio_dev *iio_dev, +const struct iio_chan_spec *chan, +int val,int val2,long m) +{ +struct mxs_lradc_adc *adc =iio_priv (iio_dev); +struct mxs_lradc_scale *scale_avail = + adc->scale_avail[chan->channel]; +int ret; + + ret =iio_device_claim_direct_mode (iio_dev); +if (ret) +return ret; + +switch (m) { +case IIO_CHAN_INFO_SCALE : + ret = -EINVAL ; +if (val == scale_avail[MXS_LRADC_DIV_DISABLED ].integer && + val2 == scale_avail[MXS_LRADC_DIV_DISABLED ].nano) { +/* divider by two disabled */ +clear_bit (chan->channel, &adc->is_divided); + ret =0 ; + }else if (val == scale_avail[MXS_LRADC_DIV_ENABLED ].integer && + val2 == scale_avail[MXS_LRADC_DIV_ENABLED ].nano) { +/* divider by two enabled */ +set_bit (chan->channel, &adc->is_divided); + ret =0 ; + } + +break ; +default : + ret = -EINVAL ; +break ; + } + +iio_device_release_direct_mode (iio_dev); + +return ret; +} + +static int mxs_lradc_adc_write_raw_get_fmt (struct iio_dev *iio_dev, +const struct iio_chan_spec *chan, +long m) +{ +return IIO_VAL_INT_PLUS_NANO ; +} + +static ssize_t mxs_lradc_adc_show_scale_avail (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct iio_dev *iio =dev_to_iio_dev (dev); +struct mxs_lradc_adc *adc =iio_priv (iio); +struct iio_dev_attr *iio_attr =to_iio_dev_attr (attr); +int i, ch, len =0 ; + + ch = iio_attr->address; +for (i =0 ; i <ARRAY_SIZE (adc->scale_avail[ch]); i++) + len +=sprintf (buf + len,"%u.%09u " , + adc->scale_avail[ch][i].integer, + adc->scale_avail[ch][i].nano); + + len +=sprintf (buf + len,"\n" ); + +return len; +} + +#define SHOW_SCALE_AVAILABLE_ATTR (ch) \ +static IIO_DEVICE_ATTR(in_voltage##ch##_scale_available, S_IRUGO, \ + mxs_lradc_adc_show_scale_avail, NULL, ch) + +SHOW_SCALE_AVAILABLE_ATTR (0 ); +SHOW_SCALE_AVAILABLE_ATTR (1 ); +SHOW_SCALE_AVAILABLE_ATTR (2 ); +SHOW_SCALE_AVAILABLE_ATTR (3 ); +SHOW_SCALE_AVAILABLE_ATTR (4 ); +SHOW_SCALE_AVAILABLE_ATTR (5 ); +SHOW_SCALE_AVAILABLE_ATTR (6 ); +SHOW_SCALE_AVAILABLE_ATTR (7 ); +SHOW_SCALE_AVAILABLE_ATTR (10 ); +SHOW_SCALE_AVAILABLE_ATTR (11 ); +SHOW_SCALE_AVAILABLE_ATTR (12 ); +SHOW_SCALE_AVAILABLE_ATTR (13 ); +SHOW_SCALE_AVAILABLE_ATTR (14 ); +SHOW_SCALE_AVAILABLE_ATTR (15 ); + +static struct attribute *mxs_lradc_adc_attributes[] = { + &iio_dev_attr_in_voltage0_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage1_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage2_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage3_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage4_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage5_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage6_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage7_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage10_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage11_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage12_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage13_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage14_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage15_scale_available.dev_attr.attr, +NULL +}; + +static const struct attribute_group mxs_lradc_adc_attribute_group = { + .attrs = mxs_lradc_adc_attributes, +}; + +static const struct iio_info mxs_lradc_adc_iio_info = { + .driver_module =THIS_MODULE , + .read_raw = mxs_lradc_adc_read_raw, + .write_raw = mxs_lradc_adc_write_raw, + .write_raw_get_fmt = mxs_lradc_adc_write_raw_get_fmt, + .attrs = &mxs_lradc_adc_attribute_group, +}; + +/* IRQ Handling */ +static irqreturn_t mxs_lradc_adc_handle_irq (int irq,void *data) +{ +struct iio_dev *iio = data; +struct mxs_lradc_adc *adc =iio_priv (iio); +struct mxs_lradc *lradc = adc->lradc; +unsigned long reg =readl (lradc->base +LRADC_CTRL1 ); +unsigned long flags; + +if (!(reg &mxs_lradc_irq_mask (lradc))) +return IRQ_NONE ; + +if (iio_buffer_enabled (iio)) { +if (reg & lradc->buffer_vchans) { +spin_lock_irqsave (&adc->lock, flags); +iio_trigger_poll (iio->trig); +spin_unlock_irqrestore (&adc->lock, flags); + } + }else if (reg &LRADC_CTRL1_LRADC_IRQ (0 )) { +complete (&adc->completion); + } + +mxs_lradc_reg_clear (lradc, reg &mxs_lradc_irq_mask (lradc), +LRADC_CTRL1 ); + +return IRQ_HANDLED ; +} + + +/* Trigger handling */ +static irqreturn_t mxs_lradc_adc_trigger_handler (int irq,void *p) +{ +struct iio_poll_func *pf = p; +struct iio_dev *iio = pf->indio_dev; +struct mxs_lradc_adc *adc =iio_priv (iio); +const u32 chan_value =LRADC_CH_ACCUMULATE | + ((LRADC_DELAY_TIMER_LOOP -1 ) <<LRADC_CH_NUM_SAMPLES_OFFSET ); +unsigned int i, j =0 ; + +for_each_set_bit (i, iio->active_scan_mask,LRADC_MAX_TOTAL_CHANS ) { + adc->buffer[j] =readl (adc->lradc->base +LRADC_CH (j)); +mxs_lradc_reg_wrt (adc->lradc, chan_value,LRADC_CH (j)); + adc->buffer[j] &=LRADC_CH_VALUE_MASK ; + adc->buffer[j] /=LRADC_DELAY_TIMER_LOOP ; + j++; + } + +iio_push_to_buffers_with_timestamp (iio, adc->buffer, pf->timestamp); + +iio_trigger_notify_done (iio->trig); + +return IRQ_HANDLED ; +} + +static int mxs_lradc_adc_configure_trigger (struct iio_trigger *trig,bool state) +{ +struct iio_dev *iio =iio_trigger_get_drvdata (trig); +struct mxs_lradc_adc *adc =iio_priv (iio); +const u32 st = state ?STMP_OFFSET_REG_SET :STMP_OFFSET_REG_CLR ; + +mxs_lradc_reg_wrt (adc->lradc,LRADC_DELAY_KICK ,LRADC_DELAY (0 ) + st); + +return 0 ; +} + +static const struct iio_trigger_ops mxs_lradc_adc_trigger_ops = { + .owner =THIS_MODULE , + .set_trigger_state = &mxs_lradc_adc_configure_trigger, +}; + +static int mxs_lradc_adc_trigger_init (struct iio_dev *iio) +{ +int ret; +struct iio_trigger *trig; +struct mxs_lradc_adc *adc =iio_priv (iio); + + trig =devm_iio_trigger_alloc (&iio->dev,"%s-dev%i" , iio->name, + iio->id); + + trig->dev.parent = adc->dev; +iio_trigger_set_drvdata (trig, iio); + trig->ops = &mxs_lradc_adc_trigger_ops; + + ret =iio_trigger_register (trig); +if (ret) +return ret; + + adc->trig = trig; + +return 0 ; +} + +static void mxs_lradc_adc_trigger_remove (struct iio_dev *iio) +{ +struct mxs_lradc_adc *adc =iio_priv (iio); + +iio_trigger_unregister (adc->trig); +} + +static int mxs_lradc_adc_buffer_preenable (struct iio_dev *iio) +{ +struct mxs_lradc_adc *adc =iio_priv (iio); +struct mxs_lradc *lradc = adc->lradc; +int chan, ofs =0 ; +unsigned long enable =0 ; +u32 ctrl4_set =0 ; +u32 ctrl4_clr =0 ; +u32 ctrl1_irq =0 ; +const u32 chan_value =LRADC_CH_ACCUMULATE | + ((LRADC_DELAY_TIMER_LOOP -1 ) <<LRADC_CH_NUM_SAMPLES_OFFSET ); + +if (lradc->soc ==IMX28_LRADC ) +mxs_lradc_reg_clear (lradc, + lradc->buffer_vchans <<LRADC_CTRL1_LRADC_IRQ_EN_OFFSET , +LRADC_CTRL1 ); +mxs_lradc_reg_clear (lradc, lradc->buffer_vchans,LRADC_CTRL0 ); + +for_each_set_bit (chan, iio->active_scan_mask,LRADC_MAX_TOTAL_CHANS ) { + ctrl4_set |= chan <<LRADC_CTRL4_LRADCSELECT_OFFSET (ofs); + ctrl4_clr |=LRADC_CTRL4_LRADCSELECT_MASK (ofs); + ctrl1_irq |=LRADC_CTRL1_LRADC_IRQ_EN (ofs); +mxs_lradc_reg_wrt (lradc, chan_value,LRADC_CH (ofs)); +bitmap_set (&enable, ofs,1 ); + ofs++; + } + +mxs_lradc_reg_clear (lradc,LRADC_DELAY_TRIGGER_LRADCS_MASK | +LRADC_DELAY_KICK ,LRADC_DELAY (0 )); +mxs_lradc_reg_clear (lradc, ctrl4_clr,LRADC_CTRL4 ); +mxs_lradc_reg_set (lradc, ctrl4_set,LRADC_CTRL4 ); +mxs_lradc_reg_set (lradc, ctrl1_irq,LRADC_CTRL1 ); +mxs_lradc_reg_set (lradc, enable <<LRADC_DELAY_TRIGGER_LRADCS_OFFSET , +LRADC_DELAY (0 )); + +return 0 ; +} + +static int mxs_lradc_adc_buffer_postdisable (struct iio_dev *iio) +{ +struct mxs_lradc_adc *adc =iio_priv (iio); +struct mxs_lradc *lradc = adc->lradc; + +mxs_lradc_reg_clear (lradc,LRADC_DELAY_TRIGGER_LRADCS_MASK | +LRADC_DELAY_KICK ,LRADC_DELAY (0 )); + +mxs_lradc_reg_clear (lradc, lradc->buffer_vchans,LRADC_CTRL0 ); +if (lradc->soc ==IMX28_LRADC ) +mxs_lradc_reg_clear (lradc, + lradc->buffer_vchans <<LRADC_CTRL1_LRADC_IRQ_EN_OFFSET , +LRADC_CTRL1 ); + +return 0 ; +} + +static bool mxs_lradc_adc_validate_scan_mask (struct iio_dev *iio, +const unsigned long *mask) +{ +struct mxs_lradc_adc *adc =iio_priv (iio); +struct mxs_lradc *lradc = adc->lradc; +const int map_chans =bitmap_weight (mask,LRADC_MAX_TOTAL_CHANS ); +int rsvd_chans =0 ; +unsigned long rsvd_mask =0 ; + +if (lradc->use_touchbutton) + rsvd_mask |=CHAN_MASK_TOUCHBUTTON ; +if (lradc->touchscreen_wire ==MXS_LRADC_TOUCHSCREEN_4WIRE ) + rsvd_mask |=CHAN_MASK_TOUCHSCREEN_4WIRE ; +if (lradc->touchscreen_wire ==MXS_LRADC_TOUCHSCREEN_5WIRE ) + rsvd_mask |=CHAN_MASK_TOUCHSCREEN_5WIRE ; + +if (lradc->use_touchbutton) + rsvd_chans++; +if (lradc->touchscreen_wire) + rsvd_chans +=2 ; + +/* Test for attempts to map channels with special mode of operation. */ +if (bitmap_intersects (mask, &rsvd_mask,LRADC_MAX_TOTAL_CHANS )) +return false; + +/* Test for attempts to map more channels then available slots. */ +if (map_chans + rsvd_chans >LRADC_MAX_MAPPED_CHANS ) +return false; + +return true; +} + +static const struct iio_buffer_setup_ops mxs_lradc_adc_buffer_ops = { + .preenable = &mxs_lradc_adc_buffer_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &mxs_lradc_adc_buffer_postdisable, + .validate_scan_mask = &mxs_lradc_adc_validate_scan_mask, +}; + +/* Driver initialization */ +#define MXS_ADC_CHAN (idx, chan_type, name) { \ + .type = (chan_type), \ + .indexed = 1, \ + .scan_index = (idx), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .channel = (idx), \ + .address = (idx), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = LRADC_RESOLUTION, \ + .storagebits = 32, \ + }, \ + .datasheet_name = (name), \ +} + +static const struct iio_chan_spec mx23_lradc_chan_spec[] = { +MXS_ADC_CHAN (0 ,IIO_VOLTAGE ,"LRADC0" ), +MXS_ADC_CHAN (1 ,IIO_VOLTAGE ,"LRADC1" ), +MXS_ADC_CHAN (2 ,IIO_VOLTAGE ,"LRADC2" ), +MXS_ADC_CHAN (3 ,IIO_VOLTAGE ,"LRADC3" ), +MXS_ADC_CHAN (4 ,IIO_VOLTAGE ,"LRADC4" ), +MXS_ADC_CHAN (5 ,IIO_VOLTAGE ,"LRADC5" ), +MXS_ADC_CHAN (6 ,IIO_VOLTAGE ,"VDDIO" ), +MXS_ADC_CHAN (7 ,IIO_VOLTAGE ,"VBATT" ), +/* Combined Temperature sensors */ + { + .type =IIO_TEMP , + .indexed =1 , + .scan_index =8 , + .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) | +BIT (IIO_CHAN_INFO_OFFSET ) | +BIT (IIO_CHAN_INFO_SCALE ), + .channel =8 , + .scan_type = {.sign ='u' , .realbits =18 , .storagebits =32 ,}, + .datasheet_name ="TEMP_DIE" , + }, +/* Hidden channel to keep indexes */ + { + .type =IIO_TEMP , + .indexed =1 , + .scan_index =-1 , + .channel =9 , + }, +MXS_ADC_CHAN (10 ,IIO_VOLTAGE ,NULL ), +MXS_ADC_CHAN (11 ,IIO_VOLTAGE ,NULL ), +MXS_ADC_CHAN (12 ,IIO_VOLTAGE ,"USB_DP" ), +MXS_ADC_CHAN (13 ,IIO_VOLTAGE ,"USB_DN" ), +MXS_ADC_CHAN (14 ,IIO_VOLTAGE ,"VBG" ), +MXS_ADC_CHAN (15 ,IIO_VOLTAGE ,"VDD5V" ), +}; + +static const struct iio_chan_spec mx28_lradc_chan_spec[] = { +MXS_ADC_CHAN (0 ,IIO_VOLTAGE ,"LRADC0" ), +MXS_ADC_CHAN (1 ,IIO_VOLTAGE ,"LRADC1" ), +MXS_ADC_CHAN (2 ,IIO_VOLTAGE ,"LRADC2" ), +MXS_ADC_CHAN (3 ,IIO_VOLTAGE ,"LRADC3" ), +MXS_ADC_CHAN (4 ,IIO_VOLTAGE ,"LRADC4" ), +MXS_ADC_CHAN (5 ,IIO_VOLTAGE ,"LRADC5" ), +MXS_ADC_CHAN (6 ,IIO_VOLTAGE ,"LRADC6" ), +MXS_ADC_CHAN (7 ,IIO_VOLTAGE ,"VBATT" ), +/* Combined Temperature sensors */ + { + .type =IIO_TEMP , + .indexed =1 , + .scan_index =8 , + .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) | +BIT (IIO_CHAN_INFO_OFFSET ) | +BIT (IIO_CHAN_INFO_SCALE ), + .channel =8 , + .scan_type = {.sign ='u' , .realbits =18 , .storagebits =32 ,}, + .datasheet_name ="TEMP_DIE" , + }, +/* Hidden channel to keep indexes */ + { + .type =IIO_TEMP , + .indexed =1 , + .scan_index =-1 , + .channel =9 , + }, +MXS_ADC_CHAN (10 ,IIO_VOLTAGE ,"VDDIO" ), +MXS_ADC_CHAN (11 ,IIO_VOLTAGE ,"VTH" ), +MXS_ADC_CHAN (12 ,IIO_VOLTAGE ,"VDDA" ), +MXS_ADC_CHAN (13 ,IIO_VOLTAGE ,"VDDD" ), +MXS_ADC_CHAN (14 ,IIO_VOLTAGE ,"VBG" ), +MXS_ADC_CHAN (15 ,IIO_VOLTAGE ,"VDD5V" ), +}; + +static void mxs_lradc_adc_hw_init (struct mxs_lradc_adc *adc) +{ +struct mxs_lradc *lradc = adc->lradc; + +/* The ADC always uses DELAY CHANNEL 0. */ +const u32 adc_cfg = + (1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET +0 )) | + (LRADC_DELAY_TIMER_PER <<LRADC_DELAY_DELAY_OFFSET ); + +/* Configure DELAY CHANNEL 0 for generic ADC sampling. */ +mxs_lradc_reg_wrt (lradc, adc_cfg,LRADC_DELAY (0 )); + +/* +* Start internal temperature sensing by clearing bit +* HW_LRADC_CTRL2_TEMPSENSE_PWD. This bit can be left cleared +* after power up. +*/ +mxs_lradc_reg_wrt (lradc,0 ,LRADC_CTRL2 ); +} + +static void mxs_lradc_adc_hw_stop (struct mxs_lradc_adc *adc) +{ +mxs_lradc_reg_wrt (adc->lradc,0 ,LRADC_DELAY (0 )); +} + +static int mxs_lradc_adc_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct mxs_lradc *lradc =dev_get_platdata (dev); +struct mxs_lradc_adc *adc; +struct iio_dev *iio; +int ret, irq, virq, i, s, n; +u64 scale_uv; +const char **irq_name; + +/* Allocate the IIO device. */ + iio =devm_iio_device_alloc (dev,sizeof (*adc)); +if (!iio) { +dev_err (dev,"Failed to allocate IIO device\n" ); +return -ENOMEM ; + } + + adc =iio_priv (iio); + adc->lradc = lradc; + adc->dev = dev; + +init_completion (&adc->completion); +spin_lock_init (&adc->lock); + +platform_set_drvdata (pdev, iio); + + iio->name = pdev->name; + iio->dev.parent = dev; + iio->dev.of_node = dev->parent->of_node; + iio->info = &mxs_lradc_adc_iio_info; + iio->modes =INDIO_DIRECT_MODE ; + iio->masklength =LRADC_MAX_TOTAL_CHANS ; + +if (lradc->soc ==IMX23_LRADC ) { + iio->channels = mx23_lradc_chan_spec; + iio->num_channels =ARRAY_SIZE (mx23_lradc_chan_spec); + irq_name = mx23_lradc_adc_irq_names; + n =ARRAY_SIZE (mx23_lradc_adc_irq_names); + }else { + iio->channels = mx28_lradc_chan_spec; + iio->num_channels =ARRAY_SIZE (mx28_lradc_chan_spec); + irq_name = mx28_lradc_adc_irq_names; + n =ARRAY_SIZE (mx28_lradc_adc_irq_names); + } + +for (i =0 ; i < n; i++) { + irq =platform_get_irq_byname (pdev, irq_name[i]); +if (irq <0 ) +return irq; + + virq =irq_of_parse_and_map (dev->parent->of_node, irq); + + ret =devm_request_irq (dev, virq, mxs_lradc_adc_handle_irq, +0 , irq_name[i], iio); +if (ret) +return ret; + } + + ret =mxs_lradc_adc_trigger_init (iio); +if (ret) + goto err_trig; + + ret =iio_triggered_buffer_setup (iio, &iio_pollfunc_store_time, + &mxs_lradc_adc_trigger_handler, + &mxs_lradc_adc_buffer_ops); +if (ret) +return ret; + + adc->vref_mv = mxs_lradc_adc_vref_mv[lradc->soc]; + +/* Populate available ADC input ranges */ +for (i =0 ; i <LRADC_MAX_TOTAL_CHANS ; i++) { +for (s =0 ; s <ARRAY_SIZE (adc->scale_avail[i]); s++) { +/* +* [s=0] = optional divider by two disabled (default) +* [s=1] = optional divider by two enabled +* +* The scale is calculated by doing: +* Vref >> (realbits - s) +* which multiplies by two on the second component +* of the array. +*/ + scale_uv = ((u64 )adc->vref_mv[i] *100000000 ) >> + (LRADC_RESOLUTION - s); + adc->scale_avail[i][s].nano = +do_div (scale_uv,100000000 ) *10 ; + adc->scale_avail[i][s].integer = scale_uv; + } + } + +/* Configure the hardware. */ +mxs_lradc_adc_hw_init (adc); + +/* Register IIO device. */ + ret =iio_device_register (iio); +if (ret) { +dev_err (dev,"Failed to register IIO device\n" ); + goto err_dev; + } + +return 0 ; + +err_dev: +mxs_lradc_adc_hw_stop (adc); +mxs_lradc_adc_trigger_remove (iio); +err_trig: +iio_triggered_buffer_cleanup (iio); +return ret; +} + +static int mxs_lradc_adc_remove (struct platform_device *pdev) +{ +struct iio_dev *iio =platform_get_drvdata (pdev); +struct mxs_lradc_adc *adc =iio_priv (iio); + +iio_device_unregister (iio); +mxs_lradc_adc_hw_stop (adc); +mxs_lradc_adc_trigger_remove (iio); +iio_triggered_buffer_cleanup (iio); + +return 0 ; +} + +static struct platform_driver mxs_lradc_adc_driver = { + .driver = { + .name ="mxs-lradc-adc" , + }, + .probe = mxs_lradc_adc_probe, + .remove = mxs_lradc_adc_remove, +}; +module_platform_driver (mxs_lradc_adc_driver); + +MODULE_AUTHOR ("Marek Vasut <[email protected]>" ); +MODULE_DESCRIPTION ("Freescale MXS LRADC driver general purpose ADC driver" ); +MODULE_LICENSE ("GPL" ); +MODULE_ALIAS ("platform:mxs-lradc-adc" );
PATCH v4 3/4 input: touchscreen: mxs-lradc: Add support for touchscreen
In reply to Ksenija StanojevicAdd 4-wire/5-wire touchscreen controller.
---
Changes in v4:
- update copyright
- use platform_get_irq_byname
- use irq_of_parse_and_map
Changes in v3:
- add MODULE_*(ALIAS, AUTHOR, DESCRIPTION)
Changes in v2:
- do not change spacing in Kconfig
- remove dev.parent
- rename err_ts_register to error
- combine functions hw_stop and disable_ts so that mxs_lradc_ts_remove could be deleted.
- add spinlock in struct mxs_lradc_ts to enable locking in interrupt handler.
- only grab irqs that are relevant to touchscreen
- use direct return instead assigning error to touch_ret in probe function.
- change licence to GPL
- add copyright
drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/mxs-lradc-ts.c | 736 +++++++++++++++++++++++++++++++ 3 files changed, 747 insertions(+) create mode 100644 drivers/input/touchscreen/mxs-lradc-ts.c
drivers/input/touchscreen/Kconfig +10 -0
@@ -305,6 +305,16 @@ config TOUCHSCREEN_EGALAX_SERIAL To compile this driver as a module, choose M here: the module will be called egalax_ts_serial. +config TOUCHSCREEN_MXS_LRADC + tristate "Freescale i.MX23/i.MX28 LRADC touchscreen" + depends on MFD_MXS_LRADC + help + Say Y here if you have a touchscreen connected to the low-resolution + analog-to-digital converter (LRADC) on an i.MX23 or i.MX28 processor. + + To compile this driver as a module, choose M here: the module will be + called mxs-lradc-ts. + config TOUCHSCREEN_FT6236 tristate "FT6236 I2C touchscreen" depends on I2C
drivers/input/touchscreen/Makefile +1 -0
@@ -52,6 +52,7 @@ obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o +obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o
drivers/input/touchscreen/mxs-lradc-ts.c new file +736 -0
736 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v4 4/4 iio: adc: mxs-lradc: Remove driver
In reply to Ksenija StanojevicSince the driver has been split into mfd there is no reason for it to stay, so remove it.
---
Changes in v4:
- nothing
Changes in v3:
- nothing
Changes in v2:
- nothing
drivers/iio/adc/Kconfig | 14 - drivers/iio/adc/Makefile | 1 - drivers/iio/adc/mxs-lradc.c | 1775 ------------------------------------------- 3 files changed, 1790 deletions(-) delete mode 100644 drivers/iio/adc/mxs-lradc.c
drivers/iio/adc/Kconfig +0 -14
@@ -310,20 +310,6 @@ config MEN_Z188_ADC This driver can also be built as a module. If so, the module will be called men_z188_adc. -config MXS_LRADC - tristate "Freescale i.MX23/i.MX28 LRADC" - depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM - depends on INPUT - select STMP_DEVICE - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for i.MX23/i.MX28 LRADC convertor - built into these chips. - - To compile this driver as a module, choose M here: the - module will be called mxs-lradc. - config NAU7802 tristate "Nuvoton NAU7802 ADC driver" depends on I2C
drivers/iio/adc/Makefile +0 -1
@@ -30,7 +30,6 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o -obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
drivers/iio/adc/mxs-lradc.c deleted +0 -1775
1,775 lines not on this page · raw message
Signature · 1 line
1.9.1