mxs-lradc: Split driver into MFD
Subsystems (6)
v11 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 (5):
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
mfd: Move binding document
.../bindings/{iio/adc => mfd}/mxs-lradc.txt | 0
drivers/iio/adc/Kconfig | 27 +-
drivers/iio/adc/Makefile | 2 +-
drivers/iio/adc/mxs-lradc-adc.c | 843 ++++++++++
drivers/iio/adc/mxs-lradc.c | 1750 --------------------
drivers/input/touchscreen/Kconfig | 10 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/mxs-lradc-ts.c | 739 +++++++++
drivers/mfd/Kconfig | 17 +
drivers/mfd/Makefile | 1 +
drivers/mfd/mxs-lradc.c | 264 +++
include/linux/mfd/mxs-lradc.h | 187 +++
12 files changed, 2076 insertions(+), 1765 deletions(-)
rename Documentation/devicetree/bindings/{iio/adc => mfd}/mxs-lradc.txt (100%)
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.hSignature · 1 line
1.9.1
PATCH v11 1/5 mfd: mxs-lradc: Add support for mxs-lradc MFD
Add core files for low resolution analog-to-digital converter (mxs-lradc) MFD driver.
---
Changes in v11:
- create static struct mfd_cells
- don't set platform data in mfd cells, set driver data instead
- remove mxs_lradc_reg_* functions, use writel function instead
Changes in v10:
- fetch base address from DT
- add a NULL check for of_match_device
Changes in v9:
- improve commit message.
Changes in v8:
- rebase onto 4.9-rc1
Changes in v7:
- define macros ADC_CELL and TSC_CELL
- remove one cell and dynamically set them in the switch()
- fail in the touchscreen driver instead of mfd driver if hardware doesn't contain a touchscreen
Changes in v6:
- update copyright
- add kernel-doc header for struct mxs-lradc
- add error message
- change EINVAL to ENODEV
- use PLATFORM_DEVID_NONE instead -1
- cosmetic fixes
Changes in v5:
- use DEFINE_RES_MEM
- don't pass ioreammaped adress to platform cells
- move comment outside of struct mxs_lradc
- change type of argument in mxs_lradc_reg_set, mxs_lradc_reg_clear, mxs_lradc_reg_wrt (struct mxs_lradc * -> void __iomem *)
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 | 264 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/mxs-lradc.h | 187 ++++++++++++++++++++++++++++++ 4 files changed, 469 insertions(+) create mode 100644 drivers/mfd/mxs-lradc.c create mode 100644 include/linux/mfd/mxs-lradc.h
drivers/mfd/Kconfig +17 -0
@@ -343,6 +343,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_MX25_TSADC tristate "Freescale i.MX25 integrated Touchscreen and ADC unit" select REGMAP_MMIO
drivers/mfd/Makefile +1 -0
@@ -212,3 +212,4 @@ obj-$(CONFIG_MFD_MT6397) += mt6397-core.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o +obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
drivers/mfd/mxs-lradc.c new file +264 -0
264 lines not on this page · raw message
include/linux/mfd/mxs-lradc.h new file +187 -0
187 lines not on this page · raw message
Signature · 1 line
1.9.1
Re: [PATCH v11 1/5] mfd: mxs-lradc: Add support for mxs-lradc MFD
Quoted 4 lines · Ksenija Stanojevic
Add core files for low resolution analog-to-digital converter (mxs-lradc) MFD driver.
Signed-off-by Ksenija Stanojevic <[email protected]>
Just a nit below.
Quoted 3 lines
+++
b/include/linux/mfd/mxs-lradc.h(quoted diff) +1
-0@@ -0,0 +1,187 @@ +/*
[...]
include/linux/mfd/mxs-lradc.h line 67
Quoted 5 lines
include/linux/mfd/mxs-lradc.h new file +5
-0+#define LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK (0x1fff << 16) +#define LRADC_CTRL1_MX23_LRADC_IRQ_EN_MASK (0x01ff << 16) +#define LRADC_CTRL1_LRADC_IRQ_EN_OFFSET 16 +#define LRADC_CTRL1_TOUCH_DETECT_IRQ BIT(8) +#define LRADC_CTRL1_LRADC_IRQ (n) (1 << (n))
This would turn into BIT(n) , no ?
Quoted 3 lines
include/linux/mfd/mxs-lradc.h new file +3
-0+#define LRADC_CTRL1_MX28_LRADC_IRQ_MASK 0x1fff +#define LRADC_CTRL1_MX23_LRADC_IRQ_MASK 0x01ff +#define LRADC_CTRL1_LRADC_IRQ_OFFSET 0
[...]
Signature · 2 lines
Best regards, Marek Vasut
Re: [PATCH v11 1/5] mfd: mxs-lradc: Add support for mxs-lradc MFD
Quoted 14 lines · Marek Vasut
Quoted 4 lines · Ksenija Stanojevic
Add core files for low resolution analog-to-digital converter (mxs-lradc) MFD driver.
Signed-off-by Ksenija Stanojevic <[email protected]>Just a nit below.
Quoted 3 lines
+++
b/include/linux/mfd/mxs-lradc.h(quoted diff) +1
-0@@ -0,0 +1,187 @@ +/*[...]
Quoted 7 lines
include/linux/mfd/mxs-lradc.h line 67
Quoted 5 lines
include/linux/mfd/mxs-lradc.h new file +5
-0+#define LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK (0x1fff << 16) +#define LRADC_CTRL1_MX23_LRADC_IRQ_EN_MASK (0x01ff << 16) +#define LRADC_CTRL1_LRADC_IRQ_EN_OFFSET 16 +#define LRADC_CTRL1_TOUCH_DETECT_IRQ BIT(8) +#define LRADC_CTRL1_LRADC_IRQ (n) (1 << (n))This would turn into BIT(n) , no ?
Once you have fixed this, you can apply my:
For my own reference:
Quoted 6 lines
Quoted 3 lines
include/linux/mfd/mxs-lradc.h new file +3
-0+#define LRADC_CTRL1_MX28_LRADC_IRQ_MASK 0x1fff +#define LRADC_CTRL1_MX23_LRADC_IRQ_MASK 0x01ff +#define LRADC_CTRL1_LRADC_IRQ_OFFSET 0[...]
Signature · 4 lines
Lee Jones Linaro STMicroelectronics Landing Team Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
PATCH v11 2/5 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 v11:
- use dev_get_drvdata instead dev_get_platdata
- use writel instead mxs_lradc_reg_* functions
Changes in v10:
- none
Changes in v9:
- none
Changes in v8:
- rebase onto 4.9-rc1
Changes in v7:
- none
Changes in v6:
- update copyright
Changes in v5:
- add field void __iomem *base to struct mxs_lradc_adc
- change arguments in all functions for accessing I/O memory to follow the previous change.
- use devm_ioremap for mapping I/O memory
Changes in v4:
- update copyright
- use platform_get_irq_byname
- use irq_of_parse_and_map
Changes in v3:
- make buffer large enough for timestamps
- remove unnecessary blank lines
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 | 843 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 857 insertions(+) create mode 100644 drivers/iio/adc/mxs-lradc-adc.c
drivers/iio/adc/Kconfig +13 -0
@@ -219,6 +219,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 FSL_MX25_ADC tristate "Freescale MX25 ADC driver" depends on MFD_MX25_TSADC
drivers/iio/adc/Makefile +1 -0
@@ -35,6 +35,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.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 +843 -0
843 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v11 3/5 input: touchscreen: mxs-lradc: Add support for touchscreen
In reply to Ksenija StanojevicAdd 4-wire/5-wire touchscreen controller.
---
Changes in v11:
- use dev_get_drvdata instead dev_get_platdata
- use writel instead mxs_lradc_reg_* functions
Changes in v10:
- none
Changes in v9:
- none
Changes in v8:
- rebase onto 4.9-rc1
Changes in v7:
- remove touch_ret variable in probe and use ret instead
- make error check on of_property_read_u32 in probe
Changes in v6:
- update copyright
Changes in v5:
- add field void __iomem *base to struct mxs_lradc_adc
- change arguments in all functions for accessing I/O memory to follow the previous change.
- use devm_ioremap for mapping I/O memory
Changes in v4:
- update copyright
- use platform_get_irq_byname
- use irq_of_parse_and_map
Changes in v3:
- make buffer large enough for timestamps
- remove unnecessary blank lines
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/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/mxs-lradc-ts.c | 739 +++++++++++++++++++++++++++++++ 3 files changed, 750 insertions(+) create mode 100644 drivers/input/touchscreen/mxs-lradc-ts.c
drivers/input/touchscreen/Kconfig +10 -0
@@ -841,6 +841,16 @@ config TOUCHSCREEN_USB_COMPOSITE To compile this driver as a module, choose M here: the module will be called usbtouchscreen. +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_MX25 tristate "Freescale i.MX25 touchscreen input driver" depends on MFD_MX25_TSADC
drivers/input/touchscreen/Makefile +1 -0
@@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o +obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
drivers/input/touchscreen/mxs-lradc-ts.c new file +739 -0
739 lines not on this page · raw message
Signature · 1 line
1.9.1
Dmitry Torokhov
maintainerRe: [PATCH v11 3/5] input: touchscreen: mxs-lradc: Add support for touchscreen
Hi Ksenija,
Quoted 174 lines · Ksenija Stanojevic
Add 4-wire/5-wire touchscreen controller.
Signed-off-by Ksenija Stanojevic <[email protected]>---
Changes in v11:
- usedev_get_drvdatainsteaddev_get_platdata
- use writel instead mxs_lradc_reg_* functionsChanges in v10:
- noneChanges in v9:
- noneChanges in v8:
- rebase onto 4.9-rc1Changes in v7:
- removetouch_retvariable in probe and use ret instead
- make error check onof_property_read_u32in probeChanges in v6:
- update copyrightChanges in v5:
- add field void__iomem*base to structmxs_lradc_adc
- change arguments in all functions for accessing I/O memory to follow the previous change.
- usedevm_ioremapfor mapping I/O memoryChanges in v4:
- update copyright
- useplatform_get_irq_byname
- useirq_of_parse_and_mapChanges in v3:
- make buffer large enough for timestamps
- remove unnecessary blank linesChanges 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/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/mxs-lradc-ts.c | 739 +++++++++++++++++++++++++++++++ 3 files changed, 750 insertions(+) create mode 100644 drivers/input/touchscreen/mxs-lradc-ts.cdrivers/input/touchscreen/Kconfig +10
-0@@ -841,6 +841,16 @@ config TOUCHSCREEN_USB_COMPOSITE To compile this driver as a module, choose M here: the module will be called usbtouchscreen. +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_MX25 tristate "Freescale i.MX25 touchscreen input driver" depends on MFD_MX25_TSADCdrivers/input/touchscreen/Makefile +1
-0@@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o +obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.odrivers/input/touchscreen/mxs-lradc-ts.c new file +75
-0@@ -0,0 +1,739 @@ +/* +* Freescale MXS LRADC touchscreen driver +* +* Copyright (c) 2012 DENX Software Engineering, GmbH. +* Copyright (c) 2016 Ksenija Stanojevic <[email protected]> +* +* 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/device.h> +#include <linux/err.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mfd/core.h> +#include <linux/mfd/mxs-lradc.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> + +const char *mxs_lradc_ts_irq_names[] = { +"mxs-lradc-touchscreen" , +"mxs-lradc-channel6" , +"mxs-lradc-channel7" , +}; + +/* +* Touchscreen handling +*/ +enum mxs_lradc_ts_plate { +LRADC_TOUCH =0 , +LRADC_SAMPLE_X , +LRADC_SAMPLE_Y , +LRADC_SAMPLE_PRESSURE , +LRADC_SAMPLE_VALID , +}; + +struct mxs_lradc_ts { +struct mxs_lradc *lradc; +struct device *dev; + +void __iomem *base; +/* +* When the touchscreen is enabled, we give it two private virtual +* channels: #6 and #7. This means that only 6 virtual channels (instead +* of 8) will be available for buffered capture. +*/ +#define TOUCHSCREEN_VCHANNEL1 7 +#define TOUCHSCREEN_VCHANNEL2 6 + +struct input_dev *ts_input; + +enum mxs_lradc_ts_plate cur_plate;/* state machine */ +bool ts_valid; +unsigned int ts_x_pos; +unsigned int ts_y_pos; +unsigned int ts_pressure; + +/* handle touchscreen's physical behaviour */ +/* samples per coordinate */ +unsigned int over_sample_cnt; +/* time clocks between samples */ +unsigned int over_sample_delay;
drivers/input/touchscreen/mxs-lradc-ts.c line 85
Quoted 10 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +10
-0+/* time in clocks to wait after the plates where switched */ +unsigned int settling_delay; +spinlock_t lock; +}; + +static u32 mxs_lradc_plate_mask (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_PLATE_MASK ; +return LRADC_CTRL0_MX28_PLATE_MASK ;
I wonder if, instead of doing conditionals on every operation, you could attach const struct pointer to your device with needed values/masks.
Quoted 612 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +612
-0+} + +static u32 mxs_lradc_touch_detect_bit (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE ; +return LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE ; +} + +static u32 mxs_lradc_drive_x_plate (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_XP |LRADC_CTRL0_MX23_XM ; +return LRADC_CTRL0_MX28_XPPSW |LRADC_CTRL0_MX28_XNNSW ; +} + +static u32 mxs_lradc_drive_y_plate (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_YP |LRADC_CTRL0_MX23_YM ; +return LRADC_CTRL0_MX28_YPPSW |LRADC_CTRL0_MX28_YNNSW ; +} + +static u32 mxs_lradc_drive_pressure (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_YP |LRADC_CTRL0_MX23_XM ; +return LRADC_CTRL0_MX28_YPPSW |LRADC_CTRL0_MX28_XNNSW ; +} + +static bool mxs_lradc_check_touch_event (struct mxs_lradc_ts *ts) +{ +return !!(readl (ts->base +LRADC_STATUS ) & +LRADC_STATUS_TOUCH_DETECT_RAW ); +} + +static void mxs_lradc_map_ts_channel (struct mxs_lradc_ts *ts,unsigned int vch, +unsigned int ch) +{ +writel (LRADC_CTRL4_LRADCSELECT_MASK (vch), + ts->base +LRADC_CTRL4 +STMP_OFFSET_REG_CLR ); +writel (LRADC_CTRL4_LRADCSELECT (vch, ch), + ts->base +LRADC_CTRL4 +STMP_OFFSET_REG_SET ); +} + +static void mxs_lradc_setup_ts_channel (struct mxs_lradc_ts *ts,unsigned int ch) +{ +/* +* prepare for oversampling conversion +* +* from the datasheet: +* "The ACCUMULATE bit in the appropriate channel register +* HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; +* otherwise, the IRQs will not fire." +*/ +writel (LRADC_CH_ACCUMULATE | +LRADC_CH_NUM_SAMPLES (ts->over_sample_cnt -1 ), + ts->base +LRADC_CH (ch)); + +/* from the datasheet: +* "Software must clear this register in preparation for a +* multi-cycle accumulation. +*/ +writel (LRADC_CH_VALUE_MASK , + ts->base +LRADC_CH (ch) +STMP_OFFSET_REG_CLR ); + +/* +* prepare the delay/loop unit according to the oversampling count +* +* from the datasheet: +* "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1, +* HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise, +* the LRADC will not trigger the delay group." +*/ +writel (LRADC_DELAY_TRIGGER (1 << ch) |LRADC_DELAY_TRIGGER_DELAYS (0 ) | +LRADC_DELAY_LOOP (ts->over_sample_cnt -1 ) | +LRADC_DELAY_DELAY (ts->over_sample_delay -1 ), + ts->base +LRADC_DELAY (3 )); + +writel (LRADC_CTRL1_LRADC_IRQ (ch), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + +/* +* after changing the touchscreen plates setting +* the signals need some initial time to settle. Start the +* SoC's delay unit and start the conversion later +* and automatically. +*/ +writel (LRADC_DELAY_TRIGGER (0 ) |LRADC_DELAY_TRIGGER_DELAYS (BIT (3 )) | +LRADC_DELAY_KICK |LRADC_DELAY_DELAY (ts->settling_delay), + ts->base +LRADC_DELAY (2 )); +} + +/* +* Pressure detection is special: +* We want to do both required measurements for the pressure detection in +* one turn. Use the hardware features to chain both conversions and let the +* hardware report one interrupt if both conversions are done +*/ +static void mxs_lradc_setup_ts_pressure (struct mxs_lradc_ts *ts, +unsigned int ch1,unsigned int ch2) +{ +u32 reg; + +/* +* prepare for oversampling conversion +* +* from the datasheet: +* "The ACCUMULATE bit in the appropriate channel register +* HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; +* otherwise, the IRQs will not fire." +*/ + reg =LRADC_CH_ACCUMULATE | +LRADC_CH_NUM_SAMPLES (ts->over_sample_cnt -1 ); +writel (reg, ts->base +LRADC_CH (ch1)); +writel (reg, ts->base +LRADC_CH (ch2)); + +/* from the datasheet: +* "Software must clear this register in preparation for a +* multi-cycle accumulation. +*/ +writel (LRADC_CH_VALUE_MASK , + ts->base +LRADC_CH (ch1) +STMP_OFFSET_REG_CLR ); +writel (LRADC_CH_VALUE_MASK , + ts->base +LRADC_CH (ch2) +STMP_OFFSET_REG_CLR ); + +/* prepare the delay/loop unit according to the oversampling count */ +writel (LRADC_DELAY_TRIGGER (1 << ch1) |LRADC_DELAY_TRIGGER (1 << ch2) | +LRADC_DELAY_TRIGGER_DELAYS (0 ) | +LRADC_DELAY_LOOP (ts->over_sample_cnt -1 ) | +LRADC_DELAY_DELAY (ts->over_sample_delay -1 ), + ts->base +LRADC_DELAY (3 )); + +writel (LRADC_CTRL1_LRADC_IRQ (ch2), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + +/* +* after changing the touchscreen plates setting +* the signals need some initial time to settle. Start the +* SoC's delay unit and start the conversion later +* and automatically. +*/ +writel (LRADC_DELAY_TRIGGER (0 ) |LRADC_DELAY_TRIGGER_DELAYS (BIT (3 )) | +LRADC_DELAY_KICK |LRADC_DELAY_DELAY (ts->settling_delay), + ts->base +LRADC_DELAY (2 )); +} + +static unsigned int mxs_lradc_ts_read_raw_channel (struct mxs_lradc_ts *ts, +unsigned int channel) +{ +u32 reg; +unsigned int num_samples, val; + + reg =readl (ts->base +LRADC_CH (channel)); +if (reg &LRADC_CH_ACCUMULATE ) + num_samples = ts->over_sample_cnt; +else + num_samples =1 ; + + val = (reg &LRADC_CH_VALUE_MASK ) >>LRADC_CH_VALUE_OFFSET ; +return val / num_samples; +} + +static unsigned int mxs_lradc_read_ts_pressure (struct mxs_lradc_ts *ts, +unsigned int ch1,unsigned int ch2) +{ +u32 reg, mask; +unsigned int pressure, m1, m2; + + mask =LRADC_CTRL1_LRADC_IRQ (ch1) |LRADC_CTRL1_LRADC_IRQ (ch2); + reg =readl (ts->base +LRADC_CTRL1 ) & mask; + +while (reg != mask) { + reg =readl (ts->base +LRADC_CTRL1 ) & mask; +dev_dbg (ts->dev,"One channel is still busy: %X\n" , reg); + } + + m1 =mxs_lradc_ts_read_raw_channel (ts, ch1); + m2 =mxs_lradc_ts_read_raw_channel (ts, ch2); + +if (m2 ==0 ) { +dev_warn (ts->dev,"Cannot calculate pressure\n" ); +return 1 << (LRADC_RESOLUTION -1 ); + } + +/* simply scale the value from 0 ... max ADC resolution */ + pressure = m1; + pressure *= (1 <<LRADC_RESOLUTION ); + pressure /= m2; + +dev_dbg (ts->dev,"Pressure = %u\n" , pressure); +return pressure; +} + +#define TS_CH_XP 2 +#define TS_CH_YP 3 +#define TS_CH_XM 4 +#define TS_CH_YM 5 + +/* +* YP(open)--+-------------+ +* | |--+ +* | | | +* YM(-)--+-------------+ | +* +--------------+ +* | | +* XP(weak+) XM(open) +* +* "weak+" means 200k Ohm VDDIO +* (-) means GND +*/ +static void mxs_lradc_setup_touch_detection (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +/* +* In order to detect a touch event the 'touch detect enable' bit +* enables: +* - a weak pullup to the X+ connector +* - a strong ground at the Y- connector +*/ +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); +writel (mxs_lradc_touch_detect_bit (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); +} + +/* +* YP(meas)--+-------------+ +* | |--+ +* | | | +* YM(open)--+-------------+ | +* +--------------+ +* | | +* XP(+) XM(-) +* +* (+) means here 1.85 V +* (-) means here GND +*/ +static void mxs_lradc_prepare_x_pos (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); +writel (mxs_lradc_drive_x_plate (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); + + ts->cur_plate =LRADC_SAMPLE_X ; +mxs_lradc_map_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ,TS_CH_YP ); +mxs_lradc_setup_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ); +} + +/* +* YP(+)--+-------------+ +* | |--+ +* | | | +* YM(-)--+-------------+ | +* +--------------+ +* | | +* XP(open) XM(meas) +* +* (+) means here 1.85 V +* (-) means here GND +*/ +static void mxs_lradc_prepare_y_pos (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); +writel (mxs_lradc_drive_y_plate (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); + + ts->cur_plate =LRADC_SAMPLE_Y ; +mxs_lradc_map_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ,TS_CH_XM ); +mxs_lradc_setup_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ); +} + +/* +* YP(+)--+-------------+ +* | |--+ +* | | | +* YM(meas)--+-------------+ | +* +--------------+ +* | | +* XP(meas) XM(-) +* +* (+) means here 1.85 V +* (-) means here GND +*/ +static void mxs_lradc_prepare_pressure (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); +writel (mxs_lradc_drive_pressure (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); + + ts->cur_plate =LRADC_SAMPLE_PRESSURE ; +mxs_lradc_map_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ,TS_CH_YM ); +mxs_lradc_map_ts_channel (ts,TOUCHSCREEN_VCHANNEL2 ,TS_CH_XP ); +mxs_lradc_setup_ts_pressure (ts,TOUCHSCREEN_VCHANNEL2 , +TOUCHSCREEN_VCHANNEL1 ); +} + +static void mxs_lradc_enable_touch_detection (struct mxs_lradc_ts *ts) +{ +mxs_lradc_setup_touch_detection (ts); + + ts->cur_plate =LRADC_TOUCH ; +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ |LRADC_CTRL1_TOUCH_DETECT_IRQ_EN , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ_EN , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_SET ); +} + +static void mxs_lradc_start_touch_event (struct mxs_lradc_ts *ts) +{ +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ_EN , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +writel (LRADC_CTRL1_LRADC_IRQ_EN (TOUCHSCREEN_VCHANNEL1 ), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_SET ); +/* +* start with the Y-pos, because it uses nearly the same plate +* settings like the touch detection +*/ +mxs_lradc_prepare_y_pos (ts); +} + +static void mxs_lradc_report_ts_event (struct mxs_lradc_ts *ts) +{ +input_report_abs (ts->ts_input,ABS_X , ts->ts_x_pos); +input_report_abs (ts->ts_input,ABS_Y , ts->ts_y_pos); +input_report_abs (ts->ts_input,ABS_PRESSURE , ts->ts_pressure); +input_report_key (ts->ts_input,BTN_TOUCH ,1 ); +input_sync (ts->ts_input); +} + +static void mxs_lradc_complete_touch_event (struct mxs_lradc_ts *ts) +{ +mxs_lradc_setup_touch_detection (ts); + ts->cur_plate =LRADC_SAMPLE_VALID ; +/* +* start a dummy conversion to burn time to settle the signals +* note: we are not interested in the conversion's value +*/ +writel (0 , ts->base +LRADC_CH (TOUCHSCREEN_VCHANNEL1 )); +writel (LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL2 ), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +writel (LRADC_DELAY_TRIGGER (1 <<TOUCHSCREEN_VCHANNEL1 ) | +LRADC_DELAY_KICK |LRADC_DELAY_DELAY (10 ), + ts->base +LRADC_DELAY (2 )); +} + +/* +* in order to avoid false measurements, report only samples where +* the surface is still touched after the position measurement +*/ +static void mxs_lradc_finish_touch_event (struct mxs_lradc_ts *ts,bool valid) +{ +/* if it is still touched, report the sample */ +if (valid &&mxs_lradc_check_touch_event (ts)) { + ts->ts_valid = true; +mxs_lradc_report_ts_event (ts); + } + +/* if it is even still touched, continue with the next measurement */ +if (mxs_lradc_check_touch_event (ts)) { +mxs_lradc_prepare_y_pos (ts); +return ; + } + +if (ts->ts_valid) { +/* signal the release */ + ts->ts_valid = false; +input_report_key (ts->ts_input,BTN_TOUCH ,0 ); +input_sync (ts->ts_input); + } + +/* if it is released, wait for the next touch via IRQ */ + ts->cur_plate =LRADC_TOUCH ; +writel (0 , ts->base +LRADC_DELAY (2 )); +writel (0 , ts->base +LRADC_DELAY (3 )); +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ | +LRADC_CTRL1_LRADC_IRQ_EN (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL1 ), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ_EN , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_SET ); +} + +/* touchscreen's state machine */ +static void mxs_lradc_handle_touch (struct mxs_lradc_ts *ts) +{ +switch (ts->cur_plate) { +case LRADC_TOUCH : +if (mxs_lradc_check_touch_event (ts)) +mxs_lradc_start_touch_event (ts); +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +return ; + +case LRADC_SAMPLE_Y : + ts->ts_y_pos = +mxs_lradc_ts_read_raw_channel (ts,TOUCHSCREEN_VCHANNEL1 ); +mxs_lradc_prepare_x_pos (ts); +return ; + +case LRADC_SAMPLE_X : + ts->ts_x_pos = +mxs_lradc_ts_read_raw_channel (ts,TOUCHSCREEN_VCHANNEL1 ); +mxs_lradc_prepare_pressure (ts); +return ; + +case LRADC_SAMPLE_PRESSURE : + ts->ts_pressure = +mxs_lradc_read_ts_pressure (ts, +TOUCHSCREEN_VCHANNEL2 , +TOUCHSCREEN_VCHANNEL1 ); +mxs_lradc_complete_touch_event (ts); +return ; + +case LRADC_SAMPLE_VALID : +mxs_lradc_finish_touch_event (ts,1 ); +break ; + } +} + +/* IRQ Handling */ +static irqreturn_t mxs_lradc_ts_handle_irq (int irq,void *data) +{ +struct mxs_lradc_ts *ts = data; +struct mxs_lradc *lradc = ts->lradc; +unsigned long reg =readl (ts->base +LRADC_CTRL1 ); +u32 clr_irq =mxs_lradc_irq_mask (lradc); +const u32 ts_irq_mask = +LRADC_CTRL1_TOUCH_DETECT_IRQ | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL2 ); +unsigned long flags; + +if (!(reg &mxs_lradc_irq_mask (lradc))) +return IRQ_NONE ; + +if (reg & ts_irq_mask) { +spin_lock_irqsave (&ts->lock, flags); +mxs_lradc_handle_touch (ts); +spin_unlock_irqrestore (&ts->lock, flags); +/* Make sure we don't clear the next conversion's interrupt. */ + clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL2 )); +writel (reg & clr_irq, + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + } + +return IRQ_HANDLED ; +} + +static int mxs_lradc_ts_open (struct input_dev *dev) +{ +struct mxs_lradc_ts *ts =input_get_drvdata (dev); + +/* Enable the touch-detect circuitry. */ +mxs_lradc_enable_touch_detection (ts); + +return 0 ; +} + +static void mxs_lradc_ts_stop (struct mxs_lradc_ts *ts) +{ +int i; +struct mxs_lradc *lradc = ts->lradc; + +/* stop all interrupts from firing */ +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ_EN | +LRADC_CTRL1_LRADC_IRQ_EN (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ_EN (TOUCHSCREEN_VCHANNEL2 ), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + +/* Power-down touchscreen touch-detect circuitry. */ +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); + +writel (lradc->buffer_vchans <<LRADC_CTRL1_LRADC_IRQ_EN_OFFSET , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + +for (i =1 ; i <LRADC_MAX_DELAY_CHANS ; i++) +writel (0 , ts->base +LRADC_DELAY (i)); +} + +static void mxs_lradc_ts_close (struct input_dev *dev) +{ +struct mxs_lradc_ts *ts =input_get_drvdata (dev); + +mxs_lradc_ts_stop (ts); +} + +static void mxs_lradc_ts_hw_init (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +/* Configure the touchscreen type */ +if (lradc->soc ==IMX28_LRADC ) { +writel (LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE , + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); + +if (lradc->touchscreen_wire ==MXS_LRADC_TOUCHSCREEN_5WIRE ) +writel (LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE , + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); + } +} + +static int mxs_lradc_ts_register (struct mxs_lradc_ts *ts) +{ +struct input_dev *input = ts->ts_input; +struct device *dev = ts->dev; + + input =devm_input_allocate_device (dev); +if (!input) +return -ENOMEM ; + + input->name ="mxs-lradc-ts" ; + input->id.bustype =BUS_HOST ; + input->open = mxs_lradc_ts_open; + input->close = mxs_lradc_ts_close; + +__set_bit (EV_ABS , input->evbit); +__set_bit (EV_KEY , input->evbit); +__set_bit (BTN_TOUCH , input->keybit); +__set_bit (INPUT_PROP_DIRECT , input->propbit); +input_set_abs_params (input,ABS_X ,0 ,LRADC_SINGLE_SAMPLE_MASK ,0 ,0 ); +input_set_abs_params (input,ABS_Y ,0 ,LRADC_SINGLE_SAMPLE_MASK ,0 ,0 ); +input_set_abs_params (input,ABS_PRESSURE ,0 ,LRADC_SINGLE_SAMPLE_MASK , +0 ,0 ); + + ts->ts_input = input; +input_set_drvdata (input, ts); + +return input_register_device (input); +} + +static int mxs_lradc_ts_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct device_node *node = dev->parent->of_node; +struct mxs_lradc *lradc =dev_get_drvdata (dev->parent); +struct mxs_lradc_ts *ts; +struct resource *iores; +int ret, irq, virq, i; +u32 ts_wires =0 , adapt; + + ts =devm_kzalloc (dev,sizeof (*ts),GFP_KERNEL ); +if (!ts) +return -ENOMEM ; + +platform_set_drvdata (pdev, ts); + + ts->lradc = lradc; + ts->dev = dev; +spin_lock_init (&ts->lock); + + iores =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + ts->base =devm_ioremap (dev, iores->start,resource_size (iores)); +if (IS_ERR (ts->base)) +return PTR_ERR (ts->base); + + ret =of_property_read_u32 (node,"fsl,lradc-touchscreen-wires" , + &ts_wires); +if (ret) +return ret; + +if (of_property_read_u32 (node,"fsl,ave-ctrl" , &adapt)) { + ts->over_sample_cnt =4 ; + }else { +if (adapt >=1 || adapt <=32 ) { + ts->over_sample_cnt = adapt; + }else { +dev_err (ts->dev,"Invalid sample count (%u)\n" , + adapt); +return -EINVAL ; + } + } + +if (of_property_read_u32 (node,"fsl,ave-delay" , &adapt)) { + ts->over_sample_delay =2 ; + }else { +if (adapt >=2 || adapt <=LRADC_DELAY_DELAY_MASK +1 ) { + ts->over_sample_delay = adapt; + }else { +dev_err (ts->dev,"Invalid sample delay (%u)\n" , + adapt); +return -EINVAL ; + } + } + +if (of_property_read_u32 (node,"fsl,settling" , &adapt)) { + ts->settling_delay =10 ; + }else { +if (adapt >=1 || adapt <=LRADC_DELAY_DELAY_MASK ) { + ts->settling_delay = adapt; + }else { +dev_err (ts->dev,"Invalid settling delay (%u)\n" , + adapt); +return -EINVAL ; + } + } + + ret =stmp_reset_block (ts->base); +if (ret)
drivers/input/touchscreen/mxs-lradc-ts.c line 707
Quoted 10 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +10
-0+return ret; + +mxs_lradc_ts_hw_init (ts); + +for (i =0 ; i <3 ; i++) { + irq =platform_get_irq_byname (pdev, mxs_lradc_ts_irq_names[i]); +if (irq <0 ) +return irq; + + virq =irq_of_parse_and_map (node, irq);
Why do we need this? I'd expect parent to fully prepare interrupts for the child to use. I.e. I'd expect I could do platform_get_irq_byname() and them go straight to devm_request_irq().
Quoted 6 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +6
-0+ + ret =devm_request_irq (dev, virq, + mxs_lradc_ts_handle_irq, +0 , mxs_lradc_ts_irq_names[i], ts); +if (ret) +return ret;
drivers/input/touchscreen/mxs-lradc-ts.c line 723
Quoted 10 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +10
-0+ } + + ret =mxs_lradc_ts_register (ts); +if (!ret) + goto error; + +return 0 ; + +error: +mxs_lradc_ts_stop (ts);
Why do you want to stop only if mxs_lradc_ts_register() fails? If open() has been called, then close() should be called on error automatically. That said, shouldn't you call mxs_lradc_ts_stop() before requesting interrupts, just to make sure they do not start firing early (even though I think it should be safe if they do)?
Thanks.
Quoted 19 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +16
-0+ +return ret; +} + +static struct platform_driver mxs_lradc_ts_driver = { + .driver = { + .name ="mxs-lradc-ts" , + }, + .probe = mxs_lradc_ts_probe, +}; +module_platform_driver (mxs_lradc_ts_driver); + +MODULE_AUTHOR ("Marek Vasut <[email protected]>" ); +MODULE_DESCRIPTION ("Freescale MXS LRADC touchscreen driver" ); +MODULE_LICENSE ("GPL" ); +MODULE_ALIAS ("platform:mxs-lradc-ts" );Signature · 1 line
1.9.1
Signature · 1 line
Dmitry
Re: [PATCH v11 3/5] input: touchscreen: mxs-lradc: Add support for touchscreen
Hi Ksenija,
[updated Fabio's mail address]
thanks for all your work on that driver.
Do you plan to submit a V13 of this patch series to address Dmitry's notes?
Best regards
Stefan
Re: [PATCH v11 3/5] input: touchscreen: mxs-lradc: Add support for touchscreen
Hi Stefan
Quoted 8 lines · Stefan Wahren
Hi Ksenija,
[updated Fabio's mail address]
thanks for all your work on that driver.
Do you plan to submit a V13 of this patch series to address Dmitry's notes?
I've been on holiday for couple of weeks, I will post new version soon.
Ksenija
Re: [PATCH v11 3/5] input: touchscreen: mxs-lradc: Add support for touchscreen
In reply to Dmitry TorokhovHi Dmitry,
Quoted 182 lines · Dmitry Torokhov
Hi Ksenija,
Quoted 179 lines · Ksenija Stanojevic
Add 4-wire/5-wire touchscreen controller.
Signed-off-by Ksenija Stanojevic <[email protected]>---
Changes in v11:
- usedev_get_drvdatainsteaddev_get_platdata
- use writel instead mxs_lradc_reg_* functionsChanges in v10:
- noneChanges in v9:
- noneChanges in v8:
- rebase onto 4.9-rc1Changes in v7:
- removetouch_retvariable in probe and use ret instead
- make error check onof_property_read_u32in probeChanges in v6:
- update copyrightChanges in v5:
- add field void__iomem*base to structmxs_lradc_adc
- change arguments in all functions for accessing I/O memory to follow the previous change.
- usedevm_ioremapfor mapping I/O memoryChanges in v4:
- update copyright
- useplatform_get_irq_byname
- useirq_of_parse_and_mapChanges in v3:
- make buffer large enough for timestamps
- remove unnecessary blank linesChanges 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/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/mxs-lradc-ts.c | 739 +++++++++++++++++++++++++++++++ 3 files changed, 750 insertions(+) create mode 100644 drivers/input/touchscreen/mxs-lradc-ts.cdrivers/input/touchscreen/Kconfig +10
-0@@ -841,6 +841,16 @@ config TOUCHSCREEN_USB_COMPOSITE To compile this driver as a module, choose M here: the module will be called usbtouchscreen. +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_MX25 tristate "Freescale i.MX25 touchscreen input driver" depends on MFD_MX25_TSADCdrivers/input/touchscreen/Makefile +1
-0@@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o +obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.odrivers/input/touchscreen/mxs-lradc-ts.c new file +80
-0@@ -0,0 +1,739 @@ +/* +* Freescale MXS LRADC touchscreen driver +* +* Copyright (c) 2012 DENX Software Engineering, GmbH. +* Copyright (c) 2016 Ksenija Stanojevic <[email protected]> +* +* 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/device.h> +#include <linux/err.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mfd/core.h> +#include <linux/mfd/mxs-lradc.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> + +const char *mxs_lradc_ts_irq_names[] = { +"mxs-lradc-touchscreen" , +"mxs-lradc-channel6" , +"mxs-lradc-channel7" , +}; + +/* +* Touchscreen handling +*/ +enum mxs_lradc_ts_plate { +LRADC_TOUCH =0 , +LRADC_SAMPLE_X , +LRADC_SAMPLE_Y , +LRADC_SAMPLE_PRESSURE , +LRADC_SAMPLE_VALID , +}; + +struct mxs_lradc_ts { +struct mxs_lradc *lradc; +struct device *dev; + +void __iomem *base; +/* +* When the touchscreen is enabled, we give it two private virtual +* channels: #6 and #7. This means that only 6 virtual channels (instead +* of 8) will be available for buffered capture. +*/ +#define TOUCHSCREEN_VCHANNEL1 7 +#define TOUCHSCREEN_VCHANNEL2 6 + +struct input_dev *ts_input; + +enum mxs_lradc_ts_plate cur_plate;/* state machine */ +bool ts_valid; +unsigned int ts_x_pos; +unsigned int ts_y_pos; +unsigned int ts_pressure; + +/* handle touchscreen's physical behaviour */ +/* samples per coordinate */ +unsigned int over_sample_cnt; +/* time clocks between samples */ +unsigned int over_sample_delay; +/* time in clocks to wait after the plates where switched */ +unsigned int settling_delay; +spinlock_t lock; +}; +
Quoted 8 lines
drivers/input/touchscreen/mxs-lradc-ts.c line 85
Quoted 5 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +5
-0+static u32 mxs_lradc_plate_mask (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_PLATE_MASK ; +return LRADC_CTRL0_MX28_PLATE_MASK ;I wonder if, instead of doing conditionals on every operation, you could attach const struct pointer to your device with needed values/masks.
Ok, I can try that.
Quoted 618 lines
Quoted 618 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +618
-0+} + +static u32 mxs_lradc_touch_detect_bit (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE ; +return LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE ; +} + +static u32 mxs_lradc_drive_x_plate (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_XP |LRADC_CTRL0_MX23_XM ; +return LRADC_CTRL0_MX28_XPPSW |LRADC_CTRL0_MX28_XNNSW ; +} + +static u32 mxs_lradc_drive_y_plate (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_YP |LRADC_CTRL0_MX23_YM ; +return LRADC_CTRL0_MX28_YPPSW |LRADC_CTRL0_MX28_YNNSW ; +} + +static u32 mxs_lradc_drive_pressure (struct mxs_lradc *lradc) +{ +if (lradc->soc ==IMX23_LRADC ) +return LRADC_CTRL0_MX23_YP |LRADC_CTRL0_MX23_XM ; +return LRADC_CTRL0_MX28_YPPSW |LRADC_CTRL0_MX28_XNNSW ; +} + +static bool mxs_lradc_check_touch_event (struct mxs_lradc_ts *ts) +{ +return !!(readl (ts->base +LRADC_STATUS ) & +LRADC_STATUS_TOUCH_DETECT_RAW ); +} + +static void mxs_lradc_map_ts_channel (struct mxs_lradc_ts *ts,unsigned int vch, +unsigned int ch) +{ +writel (LRADC_CTRL4_LRADCSELECT_MASK (vch), + ts->base +LRADC_CTRL4 +STMP_OFFSET_REG_CLR ); +writel (LRADC_CTRL4_LRADCSELECT (vch, ch), + ts->base +LRADC_CTRL4 +STMP_OFFSET_REG_SET ); +} + +static void mxs_lradc_setup_ts_channel (struct mxs_lradc_ts *ts,unsigned int ch) +{ +/* +* prepare for oversampling conversion +* +* from the datasheet: +* "The ACCUMULATE bit in the appropriate channel register +* HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; +* otherwise, the IRQs will not fire." +*/ +writel (LRADC_CH_ACCUMULATE | +LRADC_CH_NUM_SAMPLES (ts->over_sample_cnt -1 ), + ts->base +LRADC_CH (ch)); + +/* from the datasheet: +* "Software must clear this register in preparation for a +* multi-cycle accumulation. +*/ +writel (LRADC_CH_VALUE_MASK , + ts->base +LRADC_CH (ch) +STMP_OFFSET_REG_CLR ); + +/* +* prepare the delay/loop unit according to the oversampling count +* +* from the datasheet: +* "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1, +* HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise, +* the LRADC will not trigger the delay group." +*/ +writel (LRADC_DELAY_TRIGGER (1 << ch) |LRADC_DELAY_TRIGGER_DELAYS (0 ) | +LRADC_DELAY_LOOP (ts->over_sample_cnt -1 ) | +LRADC_DELAY_DELAY (ts->over_sample_delay -1 ), + ts->base +LRADC_DELAY (3 )); + +writel (LRADC_CTRL1_LRADC_IRQ (ch), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + +/* +* after changing the touchscreen plates setting +* the signals need some initial time to settle. Start the +* SoC's delay unit and start the conversion later +* and automatically. +*/ +writel (LRADC_DELAY_TRIGGER (0 ) |LRADC_DELAY_TRIGGER_DELAYS (BIT (3 )) | +LRADC_DELAY_KICK |LRADC_DELAY_DELAY (ts->settling_delay), + ts->base +LRADC_DELAY (2 )); +} + +/* +* Pressure detection is special: +* We want to do both required measurements for the pressure detection in +* one turn. Use the hardware features to chain both conversions and let the +* hardware report one interrupt if both conversions are done +*/ +static void mxs_lradc_setup_ts_pressure (struct mxs_lradc_ts *ts, +unsigned int ch1,unsigned int ch2) +{ +u32 reg; + +/* +* prepare for oversampling conversion +* +* from the datasheet: +* "The ACCUMULATE bit in the appropriate channel register +* HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; +* otherwise, the IRQs will not fire." +*/ + reg =LRADC_CH_ACCUMULATE | +LRADC_CH_NUM_SAMPLES (ts->over_sample_cnt -1 ); +writel (reg, ts->base +LRADC_CH (ch1)); +writel (reg, ts->base +LRADC_CH (ch2)); + +/* from the datasheet: +* "Software must clear this register in preparation for a +* multi-cycle accumulation. +*/ +writel (LRADC_CH_VALUE_MASK , + ts->base +LRADC_CH (ch1) +STMP_OFFSET_REG_CLR ); +writel (LRADC_CH_VALUE_MASK , + ts->base +LRADC_CH (ch2) +STMP_OFFSET_REG_CLR ); + +/* prepare the delay/loop unit according to the oversampling count */ +writel (LRADC_DELAY_TRIGGER (1 << ch1) |LRADC_DELAY_TRIGGER (1 << ch2) | +LRADC_DELAY_TRIGGER_DELAYS (0 ) | +LRADC_DELAY_LOOP (ts->over_sample_cnt -1 ) | +LRADC_DELAY_DELAY (ts->over_sample_delay -1 ), + ts->base +LRADC_DELAY (3 )); + +writel (LRADC_CTRL1_LRADC_IRQ (ch2), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + +/* +* after changing the touchscreen plates setting +* the signals need some initial time to settle. Start the +* SoC's delay unit and start the conversion later +* and automatically. +*/ +writel (LRADC_DELAY_TRIGGER (0 ) |LRADC_DELAY_TRIGGER_DELAYS (BIT (3 )) | +LRADC_DELAY_KICK |LRADC_DELAY_DELAY (ts->settling_delay), + ts->base +LRADC_DELAY (2 )); +} + +static unsigned int mxs_lradc_ts_read_raw_channel (struct mxs_lradc_ts *ts, +unsigned int channel) +{ +u32 reg; +unsigned int num_samples, val; + + reg =readl (ts->base +LRADC_CH (channel)); +if (reg &LRADC_CH_ACCUMULATE ) + num_samples = ts->over_sample_cnt; +else + num_samples =1 ; + + val = (reg &LRADC_CH_VALUE_MASK ) >>LRADC_CH_VALUE_OFFSET ; +return val / num_samples; +} + +static unsigned int mxs_lradc_read_ts_pressure (struct mxs_lradc_ts *ts, +unsigned int ch1,unsigned int ch2) +{ +u32 reg, mask; +unsigned int pressure, m1, m2; + + mask =LRADC_CTRL1_LRADC_IRQ (ch1) |LRADC_CTRL1_LRADC_IRQ (ch2); + reg =readl (ts->base +LRADC_CTRL1 ) & mask; + +while (reg != mask) { + reg =readl (ts->base +LRADC_CTRL1 ) & mask; +dev_dbg (ts->dev,"One channel is still busy: %X\n" , reg); + } + + m1 =mxs_lradc_ts_read_raw_channel (ts, ch1); + m2 =mxs_lradc_ts_read_raw_channel (ts, ch2); + +if (m2 ==0 ) { +dev_warn (ts->dev,"Cannot calculate pressure\n" ); +return 1 << (LRADC_RESOLUTION -1 ); + } + +/* simply scale the value from 0 ... max ADC resolution */ + pressure = m1; + pressure *= (1 <<LRADC_RESOLUTION ); + pressure /= m2; + +dev_dbg (ts->dev,"Pressure = %u\n" , pressure); +return pressure; +} + +#define TS_CH_XP 2 +#define TS_CH_YP 3 +#define TS_CH_XM 4 +#define TS_CH_YM 5 + +/* +* YP(open)--+-------------+ +* | |--+ +* | | | +* YM(-)--+-------------+ | +* +--------------+ +* | | +* XP(weak+) XM(open) +* +* "weak+" means 200k Ohm VDDIO +* (-) means GND +*/ +static void mxs_lradc_setup_touch_detection (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +/* +* In order to detect a touch event the 'touch detect enable' bit +* enables: +* - a weak pullup to the X+ connector +* - a strong ground at the Y- connector +*/ +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); +writel (mxs_lradc_touch_detect_bit (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); +} + +/* +* YP(meas)--+-------------+ +* | |--+ +* | | | +* YM(open)--+-------------+ | +* +--------------+ +* | | +* XP(+) XM(-) +* +* (+) means here 1.85 V +* (-) means here GND +*/ +static void mxs_lradc_prepare_x_pos (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); +writel (mxs_lradc_drive_x_plate (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); + + ts->cur_plate =LRADC_SAMPLE_X ; +mxs_lradc_map_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ,TS_CH_YP ); +mxs_lradc_setup_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ); +} + +/* +* YP(+)--+-------------+ +* | |--+ +* | | | +* YM(-)--+-------------+ | +* +--------------+ +* | | +* XP(open) XM(meas) +* +* (+) means here 1.85 V +* (-) means here GND +*/ +static void mxs_lradc_prepare_y_pos (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); +writel (mxs_lradc_drive_y_plate (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); + + ts->cur_plate =LRADC_SAMPLE_Y ; +mxs_lradc_map_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ,TS_CH_XM ); +mxs_lradc_setup_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ); +} + +/* +* YP(+)--+-------------+ +* | |--+ +* | | | +* YM(meas)--+-------------+ | +* +--------------+ +* | | +* XP(meas) XM(-) +* +* (+) means here 1.85 V +* (-) means here GND +*/ +static void mxs_lradc_prepare_pressure (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); +writel (mxs_lradc_drive_pressure (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); + + ts->cur_plate =LRADC_SAMPLE_PRESSURE ; +mxs_lradc_map_ts_channel (ts,TOUCHSCREEN_VCHANNEL1 ,TS_CH_YM ); +mxs_lradc_map_ts_channel (ts,TOUCHSCREEN_VCHANNEL2 ,TS_CH_XP ); +mxs_lradc_setup_ts_pressure (ts,TOUCHSCREEN_VCHANNEL2 , +TOUCHSCREEN_VCHANNEL1 ); +} + +static void mxs_lradc_enable_touch_detection (struct mxs_lradc_ts *ts) +{ +mxs_lradc_setup_touch_detection (ts); + + ts->cur_plate =LRADC_TOUCH ; +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ |LRADC_CTRL1_TOUCH_DETECT_IRQ_EN , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ_EN , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_SET ); +} + +static void mxs_lradc_start_touch_event (struct mxs_lradc_ts *ts) +{ +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ_EN , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +writel (LRADC_CTRL1_LRADC_IRQ_EN (TOUCHSCREEN_VCHANNEL1 ), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_SET ); +/* +* start with the Y-pos, because it uses nearly the same plate +* settings like the touch detection +*/ +mxs_lradc_prepare_y_pos (ts); +} + +static void mxs_lradc_report_ts_event (struct mxs_lradc_ts *ts) +{ +input_report_abs (ts->ts_input,ABS_X , ts->ts_x_pos); +input_report_abs (ts->ts_input,ABS_Y , ts->ts_y_pos); +input_report_abs (ts->ts_input,ABS_PRESSURE , ts->ts_pressure); +input_report_key (ts->ts_input,BTN_TOUCH ,1 ); +input_sync (ts->ts_input); +} + +static void mxs_lradc_complete_touch_event (struct mxs_lradc_ts *ts) +{ +mxs_lradc_setup_touch_detection (ts); + ts->cur_plate =LRADC_SAMPLE_VALID ; +/* +* start a dummy conversion to burn time to settle the signals +* note: we are not interested in the conversion's value +*/ +writel (0 , ts->base +LRADC_CH (TOUCHSCREEN_VCHANNEL1 )); +writel (LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL2 ), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +writel (LRADC_DELAY_TRIGGER (1 <<TOUCHSCREEN_VCHANNEL1 ) | +LRADC_DELAY_KICK |LRADC_DELAY_DELAY (10 ), + ts->base +LRADC_DELAY (2 )); +} + +/* +* in order to avoid false measurements, report only samples where +* the surface is still touched after the position measurement +*/ +static void mxs_lradc_finish_touch_event (struct mxs_lradc_ts *ts,bool valid) +{ +/* if it is still touched, report the sample */ +if (valid &&mxs_lradc_check_touch_event (ts)) { + ts->ts_valid = true; +mxs_lradc_report_ts_event (ts); + } + +/* if it is even still touched, continue with the next measurement */ +if (mxs_lradc_check_touch_event (ts)) { +mxs_lradc_prepare_y_pos (ts); +return ; + } + +if (ts->ts_valid) { +/* signal the release */ + ts->ts_valid = false; +input_report_key (ts->ts_input,BTN_TOUCH ,0 ); +input_sync (ts->ts_input); + } + +/* if it is released, wait for the next touch via IRQ */ + ts->cur_plate =LRADC_TOUCH ; +writel (0 , ts->base +LRADC_DELAY (2 )); +writel (0 , ts->base +LRADC_DELAY (3 )); +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ | +LRADC_CTRL1_LRADC_IRQ_EN (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL1 ), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ_EN , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_SET ); +} + +/* touchscreen's state machine */ +static void mxs_lradc_handle_touch (struct mxs_lradc_ts *ts) +{ +switch (ts->cur_plate) { +case LRADC_TOUCH : +if (mxs_lradc_check_touch_event (ts)) +mxs_lradc_start_touch_event (ts); +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); +return ; + +case LRADC_SAMPLE_Y : + ts->ts_y_pos = +mxs_lradc_ts_read_raw_channel (ts,TOUCHSCREEN_VCHANNEL1 ); +mxs_lradc_prepare_x_pos (ts); +return ; + +case LRADC_SAMPLE_X : + ts->ts_x_pos = +mxs_lradc_ts_read_raw_channel (ts,TOUCHSCREEN_VCHANNEL1 ); +mxs_lradc_prepare_pressure (ts); +return ; + +case LRADC_SAMPLE_PRESSURE : + ts->ts_pressure = +mxs_lradc_read_ts_pressure (ts, +TOUCHSCREEN_VCHANNEL2 , +TOUCHSCREEN_VCHANNEL1 ); +mxs_lradc_complete_touch_event (ts); +return ; + +case LRADC_SAMPLE_VALID : +mxs_lradc_finish_touch_event (ts,1 ); +break ; + } +} + +/* IRQ Handling */ +static irqreturn_t mxs_lradc_ts_handle_irq (int irq,void *data) +{ +struct mxs_lradc_ts *ts = data; +struct mxs_lradc *lradc = ts->lradc; +unsigned long reg =readl (ts->base +LRADC_CTRL1 ); +u32 clr_irq =mxs_lradc_irq_mask (lradc); +const u32 ts_irq_mask = +LRADC_CTRL1_TOUCH_DETECT_IRQ | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL2 ); +unsigned long flags; + +if (!(reg &mxs_lradc_irq_mask (lradc))) +return IRQ_NONE ; + +if (reg & ts_irq_mask) { +spin_lock_irqsave (&ts->lock, flags); +mxs_lradc_handle_touch (ts); +spin_unlock_irqrestore (&ts->lock, flags); +/* Make sure we don't clear the next conversion's interrupt. */ + clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ (TOUCHSCREEN_VCHANNEL2 )); +writel (reg & clr_irq, + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + } + +return IRQ_HANDLED ; +} + +static int mxs_lradc_ts_open (struct input_dev *dev) +{ +struct mxs_lradc_ts *ts =input_get_drvdata (dev); + +/* Enable the touch-detect circuitry. */ +mxs_lradc_enable_touch_detection (ts); + +return 0 ; +} + +static void mxs_lradc_ts_stop (struct mxs_lradc_ts *ts) +{ +int i; +struct mxs_lradc *lradc = ts->lradc; + +/* stop all interrupts from firing */ +writel (LRADC_CTRL1_TOUCH_DETECT_IRQ_EN | +LRADC_CTRL1_LRADC_IRQ_EN (TOUCHSCREEN_VCHANNEL1 ) | +LRADC_CTRL1_LRADC_IRQ_EN (TOUCHSCREEN_VCHANNEL2 ), + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + +/* Power-down touchscreen touch-detect circuitry. */ +writel (mxs_lradc_plate_mask (lradc), + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); + +writel (lradc->buffer_vchans <<LRADC_CTRL1_LRADC_IRQ_EN_OFFSET , + ts->base +LRADC_CTRL1 +STMP_OFFSET_REG_CLR ); + +for (i =1 ; i <LRADC_MAX_DELAY_CHANS ; i++) +writel (0 , ts->base +LRADC_DELAY (i)); +} + +static void mxs_lradc_ts_close (struct input_dev *dev) +{ +struct mxs_lradc_ts *ts =input_get_drvdata (dev); + +mxs_lradc_ts_stop (ts); +} + +static void mxs_lradc_ts_hw_init (struct mxs_lradc_ts *ts) +{ +struct mxs_lradc *lradc = ts->lradc; + +/* Configure the touchscreen type */ +if (lradc->soc ==IMX28_LRADC ) { +writel (LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE , + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_CLR ); + +if (lradc->touchscreen_wire ==MXS_LRADC_TOUCHSCREEN_5WIRE ) +writel (LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE , + ts->base +LRADC_CTRL0 +STMP_OFFSET_REG_SET ); + } +} + +static int mxs_lradc_ts_register (struct mxs_lradc_ts *ts) +{ +struct input_dev *input = ts->ts_input; +struct device *dev = ts->dev; + + input =devm_input_allocate_device (dev); +if (!input) +return -ENOMEM ; + + input->name ="mxs-lradc-ts" ; + input->id.bustype =BUS_HOST ; + input->open = mxs_lradc_ts_open; + input->close = mxs_lradc_ts_close; + +__set_bit (EV_ABS , input->evbit); +__set_bit (EV_KEY , input->evbit); +__set_bit (BTN_TOUCH , input->keybit); +__set_bit (INPUT_PROP_DIRECT , input->propbit); +input_set_abs_params (input,ABS_X ,0 ,LRADC_SINGLE_SAMPLE_MASK ,0 ,0 ); +input_set_abs_params (input,ABS_Y ,0 ,LRADC_SINGLE_SAMPLE_MASK ,0 ,0 ); +input_set_abs_params (input,ABS_PRESSURE ,0 ,LRADC_SINGLE_SAMPLE_MASK , +0 ,0 ); + + ts->ts_input = input; +input_set_drvdata (input, ts); + +return input_register_device (input); +} + +static int mxs_lradc_ts_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct device_node *node = dev->parent->of_node; +struct mxs_lradc *lradc =dev_get_drvdata (dev->parent); +struct mxs_lradc_ts *ts; +struct resource *iores; +int ret, irq, virq, i; +u32 ts_wires =0 , adapt; + + ts =devm_kzalloc (dev,sizeof (*ts),GFP_KERNEL ); +if (!ts) +return -ENOMEM ; + +platform_set_drvdata (pdev, ts); + + ts->lradc = lradc; + ts->dev = dev; +spin_lock_init (&ts->lock); + + iores =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + ts->base =devm_ioremap (dev, iores->start,resource_size (iores)); +if (IS_ERR (ts->base)) +return PTR_ERR (ts->base); + + ret =of_property_read_u32 (node,"fsl,lradc-touchscreen-wires" , + &ts_wires); +if (ret) +return ret; + +if (of_property_read_u32 (node,"fsl,ave-ctrl" , &adapt)) { + ts->over_sample_cnt =4 ; + }else { +if (adapt >=1 || adapt <=32 ) { + ts->over_sample_cnt = adapt; + }else { +dev_err (ts->dev,"Invalid sample count (%u)\n" , + adapt); +return -EINVAL ; + } + } + +if (of_property_read_u32 (node,"fsl,ave-delay" , &adapt)) { + ts->over_sample_delay =2 ; + }else { +if (adapt >=2 || adapt <=LRADC_DELAY_DELAY_MASK +1 ) { + ts->over_sample_delay = adapt; + }else { +dev_err (ts->dev,"Invalid sample delay (%u)\n" , + adapt); +return -EINVAL ; + } + } + +if (of_property_read_u32 (node,"fsl,settling" , &adapt)) { + ts->settling_delay =10 ; + }else { +if (adapt >=1 || adapt <=LRADC_DELAY_DELAY_MASK ) { + ts->settling_delay = adapt; + }else { +dev_err (ts->dev,"Invalid settling delay (%u)\n" , + adapt); +return -EINVAL ; + } + } + + ret =stmp_reset_block (ts->base); +if (ret) +return ret; + +mxs_lradc_ts_hw_init (ts); + +for (i =0 ; i <3 ; i++) { + irq =platform_get_irq_byname (pdev, mxs_lradc_ts_irq_names[i]);
Quoted 8 lines
drivers/input/touchscreen/mxs-lradc-ts.c line 707
Quoted 4 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +4
-0+if (irq <0 ) +return irq; + + virq =irq_of_parse_and_map (node, irq);Why do we need this? I'd expect parent to fully prepare interrupts for the child to use. I.e. I'd expect I could do
platform_get_irq_byname()and them go straight todevm_request_irq().
Well probe fails and devm_request_irq trows error -22 in that case, so I think that use of irq_of_parse_and_map is needed.
Quoted 14 lines
Quoted 14 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +14
-0+ + ret =devm_request_irq (dev, virq, + mxs_lradc_ts_handle_irq, +0 , mxs_lradc_ts_irq_names[i], ts); +if (ret) +return ret; + } + + ret =mxs_lradc_ts_register (ts); +if (!ret) + goto error; + +return 0 ; +
Quoted 8 lines
drivers/input/touchscreen/mxs-lradc-ts.c line 723
Quoted 2 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +2
-0+error: +mxs_lradc_ts_stop (ts);Why do you want to stop only if
mxs_lradc_ts_register()fails? Ifopen()has been called, thenclose()should be called on error automatically. That said, shouldn't you callmxs_lradc_ts_stop()before requesting interrupts, just to make sure they do not start firing early (even though I think it should be safe if they do)?
Ok, I will do that.
Thanks,
Ksenija
Quoted 24 lines
Thanks.
Quoted 17 lines
drivers/input/touchscreen/mxs-lradc-ts.c new file +16
-1+ +return ret; +} + +static struct platform_driver mxs_lradc_ts_driver = { + .driver = { + .name ="mxs-lradc-ts" , + }, + .probe = mxs_lradc_ts_probe, +}; +module_platform_driver (mxs_lradc_ts_driver); + +MODULE_AUTHOR ("Marek Vasut <[email protected]>" ); +MODULE_DESCRIPTION ("Freescale MXS LRADC touchscreen driver" ); +MODULE_LICENSE ("GPL" ); +MODULE_ALIAS ("platform:mxs-lradc-ts" ); --Quoted 2 lines
1.9.1
--
Dmitry
PATCH v11 4/5 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 v11:
- none
Changes in v10:
- none
Changes in v9:
- none
Changes in v8:
- rebase onto 4.9-rc1
Changes in v7:
- none
Changes in v6:
- none
Changes in v5:
- none
Changes in v4:
- none
Changes in v3:
- none
Changes in v2:
- add to the patchset
drivers/iio/adc/Kconfig | 14 - drivers/iio/adc/Makefile | 1 - drivers/iio/adc/mxs-lradc.c | 1750 ------------------------------------------- 3 files changed, 1765 deletions(-) delete mode 100644 drivers/iio/adc/mxs-lradc.c
drivers/iio/adc/Kconfig +0 -14
@@ -374,20 +374,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
@@ -36,7 +36,6 @@ obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.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 -1750
1,750 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v11 5/5 mfd: Move binding document
In reply to Ksenija StanojevicThe bindings, which are now used in MFD, need also to be documented in the MFD binding document.
---
Changes in v11:
- none
Changes in v10:
- none
Changes in v9:
- format patch using -M option
Changes in v8:
- rebase onto 4.9-rc1
Changes in v7:
- add to the patchset
Documentation/devicetree/bindings/{iio/adc => mfd}/mxs-lradc.txt | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename Documentation/devicetree/bindings/{iio/adc => mfd}/mxs-lradc.txt (100%)Documentation/devicetree/bindings/mfd/mxs-lradc.txt renamed from Documentation/devicetree/bindings/iio/adc/mxs-lradc.txt +0 -0
Signature · 1 line
1.9.1
Re: [PATCH v11 5/5] mfd: Move binding document
Quoted 4 lines · Ksenija Stanojevic
The bindings, which are now used in MFD, need also to be documented in the MFD binding document.
Signed-off-by Ksenija Stanojevic <[email protected]>
For my own reference:
Quoted 24 lines
---
Changes in v11:
- noneChanges in v10:
- noneChanges in v9:
- format patch using -M optionChanges in v8:
- rebase onto 4.9-rc1Changes in v7:
- add to the patchsetDocumentation/devicetree/bindings/{iio/adc => mfd}/mxs-lradc.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/devicetree/bindings/{iio/adc => mfd}/mxs-lradc.txt (100%)Documentation/devicetree/bindings/mfd/mxs-lradc.txt renamed from Documentation/devicetree/bindings/iio/adc/mxs-lradc.txt +0
-0
Signature · 4 lines
Lee Jones Linaro STMicroelectronics Landing Team Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
Quoted 23 lines · Ksenija Stanojevic
Split existing driver mxs-lradc into MFD with touchscreen and IIO part.
Tested on I.MX28
Ksenija Stanojevic (5):
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
mfd: Move binding document.../bindings/{iio/adc => mfd}/mxs-lradc.txt | 0 drivers/iio/adc/Kconfig | 27 +- drivers/iio/adc/Makefile | 2 +- drivers/iio/adc/mxs-lradc-adc.c | 843 ++++++++++ drivers/iio/adc/mxs-lradc.c | 1750 -------------------- drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/mxs-lradc-ts.c | 739 +++++++++ drivers/mfd/Kconfig | 17 + drivers/mfd/Makefile | 1 + drivers/mfd/mxs-lradc.c | 264 +++
Quoted 9 lines
include/linux/mfd/mxs-lradc.h | 187 +++
12 files changed, 2076 insertions(+), 1765 deletions(-)
rename Documentation/devicetree/bindings/{iio/adc => mfd}/mxs-lradc.txt (100%)
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.hExcept minor nit in 1/5, the whole series is:
Signature · 2 lines
Best regards, Marek Vasut