Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
53431d0a
Commit
53431d0a
authored
Sep 11, 2015
by
Dmitry Torokhov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'next' into for-linus
Prepare second round of input updates for 4.3 merge window.
parents
01b944fe
ade9c1a4
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
1019 additions
and
15 deletions
+1019
-15
Documentation/devicetree/bindings/input/touchscreen/colibri-vf50-ts.txt
...devicetree/bindings/input/touchscreen/colibri-vf50-ts.txt
+36
-0
Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
...tion/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
+36
-0
drivers/input/evdev.c
drivers/input/evdev.c
+4
-9
drivers/input/keyboard/imx_keypad.c
drivers/input/keyboard/imx_keypad.c
+0
-2
drivers/input/misc/ab8500-ponkey.c
drivers/input/misc/ab8500-ponkey.c
+1
-0
drivers/input/misc/pwm-beeper.c
drivers/input/misc/pwm-beeper.c
+1
-0
drivers/input/misc/regulator-haptic.c
drivers/input/misc/regulator-haptic.c
+1
-0
drivers/input/misc/sparcspkr.c
drivers/input/misc/sparcspkr.c
+2
-0
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/elan_i2c_core.c
+1
-0
drivers/input/serio/i8042.c
drivers/input/serio/i8042.c
+1
-1
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Kconfig
+24
-0
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/Makefile
+2
-0
drivers/input/touchscreen/colibri-vf50-ts.c
drivers/input/touchscreen/colibri-vf50-ts.c
+386
-0
drivers/input/touchscreen/cyttsp4_i2c.c
drivers/input/touchscreen/cyttsp4_i2c.c
+0
-1
drivers/input/touchscreen/cyttsp_i2c.c
drivers/input/touchscreen/cyttsp_i2c.c
+0
-1
drivers/input/touchscreen/elants_i2c.c
drivers/input/touchscreen/elants_i2c.c
+1
-1
drivers/input/touchscreen/imx6ul_tsc.c
drivers/input/touchscreen/imx6ul_tsc.c
+523
-0
No files found.
Documentation/devicetree/bindings/input/touchscreen/colibri-vf50-ts.txt
0 → 100644
View file @
53431d0a
* Toradex Colibri VF50 Touchscreen driver
Required Properties:
- compatible must be toradex,vf50-touchscreen
- io-channels: adc channels being used by the Colibri VF50 module
- xp-gpios: FET gate driver for input of X+
- xm-gpios: FET gate driver for input of X-
- yp-gpios: FET gate driver for input of Y+
- ym-gpios: FET gate driver for input of Y-
- interrupt-parent: phandle for the interrupt controller
- interrupts: pen irq interrupt for touch detection
- pinctrl-names: "idle", "default", "gpios"
- pinctrl-0: pinctrl node for pen/touch detection state pinmux
- pinctrl-1: pinctrl node for X/Y and pressure measurement (ADC) state pinmux
- pinctrl-2: pinctrl node for gpios functioning as FET gate drivers
- vf50-ts-min-pressure: pressure level at which to stop measuring X/Y values
Example:
touchctrl: vf50_touchctrl {
compatible = "toradex,vf50-touchscreen";
io-channels = <&adc1 0>,<&adc0 0>,
<&adc0 1>,<&adc1 2>;
xp-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
xm-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
yp-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
ym-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
interrupt-parent = <&gpio0>;
interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "idle","default","gpios";
pinctrl-0 = <&pinctrl_touchctrl_idle>;
pinctrl-1 = <&pinctrl_touchctrl_default>;
pinctrl-2 = <&pinctrl_touchctrl_gpios>;
vf50-ts-min-pressure = <200>;
status = "disabled";
};
Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
0 → 100644
View file @
53431d0a
* Freescale i.MX6UL Touch Controller
Required properties:
- compatible: must be "fsl,imx6ul-tsc".
- reg: this touch controller address and the ADC2 address.
- interrupts: the interrupt of this touch controller and ADC2.
- clocks: the root clock of touch controller and ADC2.
- clock-names; must be "tsc" and "adc".
- xnur-gpio: the X- gpio this controller connect to.
This xnur-gpio returns to low once the finger leave the touch screen (The
last touch event the touch controller capture).
Optional properties:
- measure-delay-time: the value of measure delay time.
Before X-axis or Y-axis measurement, the screen need some time before
even potential distribution ready.
This value depends on the touch screen.
- pre-charge-time: the touch screen need some time to precharge.
This value depends on the touch screen.
Example:
tsc: tsc@02040000 {
compatible = "fsl,imx6ul-tsc";
reg = <0x02040000 0x4000>, <0x0219c000 0x4000>;
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_IPG>,
<&clks IMX6UL_CLK_ADC2>;
clock-names = "tsc", "adc";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_tsc>;
xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
measure-delay-time = <0xfff>;
pre-charge-time = <0xffff>;
status = "okay";
};
drivers/input/evdev.c
View file @
53431d0a
...
...
@@ -290,19 +290,14 @@ static int evdev_flush(struct file *file, fl_owner_t id)
{
struct
evdev_client
*
client
=
file
->
private_data
;
struct
evdev
*
evdev
=
client
->
evdev
;
int
retval
;
retval
=
mutex_lock_interruptible
(
&
evdev
->
mutex
);
if
(
retval
)
return
retval
;
mutex_lock
(
&
evdev
->
mutex
);
if
(
!
evdev
->
exist
||
client
->
revoked
)
retval
=
-
ENODEV
;
else
retval
=
input_flush_device
(
&
evdev
->
handle
,
file
);
if
(
evdev
->
exist
&&
!
client
->
revoked
)
input_flush_device
(
&
evdev
->
handle
,
file
);
mutex_unlock
(
&
evdev
->
mutex
);
return
retval
;
return
0
;
}
static
void
evdev_free
(
struct
device
*
dev
)
...
...
drivers/input/keyboard/imx_keypad.c
View file @
53431d0a
...
...
@@ -5,8 +5,6 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* <<Power management needs to be implemented>>.
*/
#include <linux/clk.h>
...
...
drivers/input/misc/ab8500-ponkey.c
View file @
53431d0a
...
...
@@ -118,6 +118,7 @@ static const struct of_device_id ab8500_ponkey_match[] = {
{
.
compatible
=
"stericsson,ab8500-ponkey"
,
},
{}
};
MODULE_DEVICE_TABLE
(
of
,
ab8500_ponkey_match
);
#endif
static
struct
platform_driver
ab8500_ponkey_driver
=
{
...
...
drivers/input/misc/pwm-beeper.c
View file @
53431d0a
...
...
@@ -173,6 +173,7 @@ static const struct of_device_id pwm_beeper_match[] = {
{
.
compatible
=
"pwm-beeper"
,
},
{
},
};
MODULE_DEVICE_TABLE
(
of
,
pwm_beeper_match
);
#endif
static
struct
platform_driver
pwm_beeper_driver
=
{
...
...
drivers/input/misc/regulator-haptic.c
View file @
53431d0a
...
...
@@ -249,6 +249,7 @@ static const struct of_device_id regulator_haptic_dt_match[] = {
{
.
compatible
=
"regulator-haptic"
},
{
/* sentinel */
},
};
MODULE_DEVICE_TABLE
(
of
,
regulator_haptic_dt_match
);
static
struct
platform_driver
regulator_haptic_driver
=
{
.
probe
=
regulator_haptic_probe
,
...
...
drivers/input/misc/sparcspkr.c
View file @
53431d0a
...
...
@@ -253,6 +253,7 @@ static const struct of_device_id bbc_beep_match[] = {
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
bbc_beep_match
);
static
struct
platform_driver
bbc_beep_driver
=
{
.
driver
=
{
...
...
@@ -332,6 +333,7 @@ static const struct of_device_id grover_beep_match[] = {
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
grover_beep_match
);
static
struct
platform_driver
grover_beep_driver
=
{
.
driver
=
{
...
...
drivers/input/mouse/elan_i2c_core.c
View file @
53431d0a
...
...
@@ -1170,6 +1170,7 @@ static const struct acpi_device_id elan_acpi_id[] = {
{
"ELAN0000"
,
0
},
{
"ELAN0100"
,
0
},
{
"ELAN0600"
,
0
},
{
"ELAN1000"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
acpi
,
elan_acpi_id
);
...
...
drivers/input/serio/i8042.c
View file @
53431d0a
...
...
@@ -877,7 +877,7 @@ static int __init i8042_check_aux(void)
static
int
i8042_controller_check
(
void
)
{
if
(
i8042_flush
())
{
pr_
err
(
"No controller found
\n
"
);
pr_
info
(
"No controller found
\n
"
);
return
-
ENODEV
;
}
...
...
drivers/input/touchscreen/Kconfig
View file @
53431d0a
...
...
@@ -479,6 +479,18 @@ config TOUCHSCREEN_MTOUCH
To compile this driver as a module, choose M here: the
module will be called mtouch.
config TOUCHSCREEN_IMX6UL_TSC
tristate "Freescale i.MX6UL touchscreen controller"
depends on (OF && GPIOLIB) || COMPILE_TEST
help
Say Y here if you have a Freescale i.MX6UL, and want to
use the internal touchscreen controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called imx6ul_tsc.
config TOUCHSCREEN_INEXIO
tristate "iNexio serial touchscreens"
select SERIO
...
...
@@ -1040,4 +1052,16 @@ config TOUCHSCREEN_ZFORCE
To compile this driver as a module, choose M here: the
module will be called zforce_ts.
config TOUCHSCREEN_COLIBRI_VF50
tristate "Toradex Colibri on board touchscreen driver"
depends on GPIOLIB && IIO && VF610_ADC
help
Say Y here if you have a Colibri VF50 and plan to use
the on-board provided 4-wire touchscreen driver.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called colibri_vf50_ts.
endif
drivers/input/touchscreen/Makefile
View file @
53431d0a
...
...
@@ -38,6 +38,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU)
+=
fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX)
+=
goodix.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X)
+=
ili210x.o
obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC)
+=
imx6ul_tsc.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO)
+=
inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)
+=
intel-mid-touch.o
obj-$(CONFIG_TOUCHSCREEN_IPROC)
+=
bcm_iproc_tsc.o
...
...
@@ -85,3 +86,4 @@ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_SX8654)
+=
sx8654.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X)
+=
tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_ZFORCE)
+=
zforce_ts.o
obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50)
+=
colibri-vf50-ts.o
drivers/input/touchscreen/colibri-vf50-ts.c
0 → 100644
View file @
53431d0a
/*
* Toradex Colibri VF50 Touchscreen driver
*
* Copyright 2015 Toradex AG
*
* Originally authored by Stefan Agner for 3.0 kernel
*
* 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.
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/consumer.h>
#include <linux/iio/types.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#define DRIVER_NAME "colibri-vf50-ts"
#define DRV_VERSION "1.0"
#define VF_ADC_MAX ((1 << 12) - 1)
#define COLI_TOUCH_MIN_DELAY_US 1000
#define COLI_TOUCH_MAX_DELAY_US 2000
#define COLI_PULLUP_MIN_DELAY_US 10000
#define COLI_PULLUP_MAX_DELAY_US 11000
#define COLI_TOUCH_NO_OF_AVGS 5
#define COLI_TOUCH_REQ_ADC_CHAN 4
struct
vf50_touch_device
{
struct
platform_device
*
pdev
;
struct
input_dev
*
ts_input
;
struct
iio_channel
*
channels
;
struct
gpio_desc
*
gpio_xp
;
struct
gpio_desc
*
gpio_xm
;
struct
gpio_desc
*
gpio_yp
;
struct
gpio_desc
*
gpio_ym
;
int
pen_irq
;
int
min_pressure
;
bool
stop_touchscreen
;
};
/*
* Enables given plates and measures touch parameters using ADC
*/
static
int
adc_ts_measure
(
struct
iio_channel
*
channel
,
struct
gpio_desc
*
plate_p
,
struct
gpio_desc
*
plate_m
)
{
int
i
,
value
=
0
,
val
=
0
;
int
error
;
gpiod_set_value
(
plate_p
,
1
);
gpiod_set_value
(
plate_m
,
1
);
usleep_range
(
COLI_TOUCH_MIN_DELAY_US
,
COLI_TOUCH_MAX_DELAY_US
);
for
(
i
=
0
;
i
<
COLI_TOUCH_NO_OF_AVGS
;
i
++
)
{
error
=
iio_read_channel_raw
(
channel
,
&
val
);
if
(
error
<
0
)
{
value
=
error
;
goto
error_iio_read
;
}
value
+=
val
;
}
value
/=
COLI_TOUCH_NO_OF_AVGS
;
error_iio_read:
gpiod_set_value
(
plate_p
,
0
);
gpiod_set_value
(
plate_m
,
0
);
return
value
;
}
/*
* Enable touch detection using falling edge detection on XM
*/
static
void
vf50_ts_enable_touch_detection
(
struct
vf50_touch_device
*
vf50_ts
)
{
/* Enable plate YM (needs to be strong GND, high active) */
gpiod_set_value
(
vf50_ts
->
gpio_ym
,
1
);
/*
* Let the platform mux to idle state in order to enable
* Pull-Up on GPIO
*/
pinctrl_pm_select_idle_state
(
&
vf50_ts
->
pdev
->
dev
);
/* Wait for the pull-up to be stable on high */
usleep_range
(
COLI_PULLUP_MIN_DELAY_US
,
COLI_PULLUP_MAX_DELAY_US
);
}
/*
* ADC touch screen sampling bottom half irq handler
*/
static
irqreturn_t
vf50_ts_irq_bh
(
int
irq
,
void
*
private
)
{
struct
vf50_touch_device
*
vf50_ts
=
private
;
struct
device
*
dev
=
&
vf50_ts
->
pdev
->
dev
;
int
val_x
,
val_y
,
val_z1
,
val_z2
,
val_p
=
0
;
bool
discard_val_on_start
=
true
;
/* Disable the touch detection plates */
gpiod_set_value
(
vf50_ts
->
gpio_ym
,
0
);
/* Let the platform mux to default state in order to mux as ADC */
pinctrl_pm_select_default_state
(
dev
);
while
(
!
vf50_ts
->
stop_touchscreen
)
{
/* X-Direction */
val_x
=
adc_ts_measure
(
&
vf50_ts
->
channels
[
0
],
vf50_ts
->
gpio_xp
,
vf50_ts
->
gpio_xm
);
if
(
val_x
<
0
)
break
;
/* Y-Direction */
val_y
=
adc_ts_measure
(
&
vf50_ts
->
channels
[
1
],
vf50_ts
->
gpio_yp
,
vf50_ts
->
gpio_ym
);
if
(
val_y
<
0
)
break
;
/*
* Touch pressure
* Measure on XP/YM
*/
val_z1
=
adc_ts_measure
(
&
vf50_ts
->
channels
[
2
],
vf50_ts
->
gpio_yp
,
vf50_ts
->
gpio_xm
);
if
(
val_z1
<
0
)
break
;
val_z2
=
adc_ts_measure
(
&
vf50_ts
->
channels
[
3
],
vf50_ts
->
gpio_yp
,
vf50_ts
->
gpio_xm
);
if
(
val_z2
<
0
)
break
;
/* Validate signal (avoid calculation using noise) */
if
(
val_z1
>
64
&&
val_x
>
64
)
{
/*
* Calculate resistance between the plates
* lower resistance means higher pressure
*/
int
r_x
=
(
1000
*
val_x
)
/
VF_ADC_MAX
;
val_p
=
(
r_x
*
val_z2
)
/
val_z1
-
r_x
;
}
else
{
val_p
=
2000
;
}
val_p
=
2000
-
val_p
;
dev_dbg
(
dev
,
"Measured values: x: %d, y: %d, z1: %d, z2: %d, p: %d
\n
"
,
val_x
,
val_y
,
val_z1
,
val_z2
,
val_p
);
/*
* If touch pressure is too low, stop measuring and reenable
* touch detection
*/
if
(
val_p
<
vf50_ts
->
min_pressure
||
val_p
>
2000
)
break
;
/*
* The pressure may not be enough for the first x and the
* second y measurement, but, the pressure is ok when the
* driver is doing the third and fourth measurement. To
* take care of this, we drop the first measurement always.
*/
if
(
discard_val_on_start
)
{
discard_val_on_start
=
false
;
}
else
{
/*
* Report touch position and sleep for
* the next measurement.
*/
input_report_abs
(
vf50_ts
->
ts_input
,
ABS_X
,
VF_ADC_MAX
-
val_x
);
input_report_abs
(
vf50_ts
->
ts_input
,
ABS_Y
,
VF_ADC_MAX
-
val_y
);
input_report_abs
(
vf50_ts
->
ts_input
,
ABS_PRESSURE
,
val_p
);
input_report_key
(
vf50_ts
->
ts_input
,
BTN_TOUCH
,
1
);
input_sync
(
vf50_ts
->
ts_input
);
}
usleep_range
(
COLI_PULLUP_MIN_DELAY_US
,
COLI_PULLUP_MAX_DELAY_US
);
}
/* Report no more touch, re-enable touch detection */
input_report_abs
(
vf50_ts
->
ts_input
,
ABS_PRESSURE
,
0
);
input_report_key
(
vf50_ts
->
ts_input
,
BTN_TOUCH
,
0
);
input_sync
(
vf50_ts
->
ts_input
);
vf50_ts_enable_touch_detection
(
vf50_ts
);
return
IRQ_HANDLED
;
}
static
int
vf50_ts_open
(
struct
input_dev
*
dev_input
)
{
struct
vf50_touch_device
*
touchdev
=
input_get_drvdata
(
dev_input
);
struct
device
*
dev
=
&
touchdev
->
pdev
->
dev
;
dev_dbg
(
dev
,
"Input device %s opened, starting touch detection
\n
"
,
dev_input
->
name
);
touchdev
->
stop_touchscreen
=
false
;
/* Mux detection before request IRQ, wait for pull-up to settle */
vf50_ts_enable_touch_detection
(
touchdev
);
return
0
;
}
static
void
vf50_ts_close
(
struct
input_dev
*
dev_input
)
{
struct
vf50_touch_device
*
touchdev
=
input_get_drvdata
(
dev_input
);
struct
device
*
dev
=
&
touchdev
->
pdev
->
dev
;
touchdev
->
stop_touchscreen
=
true
;
/* Make sure IRQ is not running past close */
mb
();
synchronize_irq
(
touchdev
->
pen_irq
);
gpiod_set_value
(
touchdev
->
gpio_ym
,
0
);
pinctrl_pm_select_default_state
(
dev
);
dev_dbg
(
dev
,
"Input device %s closed, disable touch detection
\n
"
,
dev_input
->
name
);
}
static
int
vf50_ts_get_gpiod
(
struct
device
*
dev
,
struct
gpio_desc
**
gpio_d
,
const
char
*
con_id
,
enum
gpiod_flags
flags
)
{
int
error
;
*
gpio_d
=
devm_gpiod_get
(
dev
,
con_id
,
flags
);
if
(
IS_ERR
(
*
gpio_d
))
{
error
=
PTR_ERR
(
*
gpio_d
);
dev_err
(
dev
,
"Could not get gpio_%s %d
\n
"
,
con_id
,
error
);
return
error
;
}
return
0
;
}
static
void
vf50_ts_channel_release
(
void
*
data
)
{
struct
iio_channel
*
channels
=
data
;
iio_channel_release_all
(
channels
);
}
static
int
vf50_ts_probe
(
struct
platform_device
*
pdev
)
{
struct
input_dev
*
input
;
struct
iio_channel
*
channels
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
vf50_touch_device
*
touchdev
;
int
num_adc_channels
;
int
error
;
channels
=
iio_channel_get_all
(
dev
);
if
(
IS_ERR
(
channels
))
return
PTR_ERR
(
channels
);
error
=
devm_add_action
(
dev
,
vf50_ts_channel_release
,
channels
);
if
(
error
)
{
iio_channel_release_all
(
channels
);
dev_err
(
dev
,
"Failed to register iio channel release action"
);
return
error
;
}
num_adc_channels
=
0
;
while
(
channels
[
num_adc_channels
].
indio_dev
)
num_adc_channels
++
;
if
(
num_adc_channels
!=
COLI_TOUCH_REQ_ADC_CHAN
)
{
dev_err
(
dev
,
"Inadequate ADC channels specified
\n
"
);
return
-
EINVAL
;
}
touchdev
=
devm_kzalloc
(
dev
,
sizeof
(
*
touchdev
),
GFP_KERNEL
);
if
(
!
touchdev
)
return
-
ENOMEM
;
touchdev
->
pdev
=
pdev
;
touchdev
->
channels
=
channels
;
error
=
of_property_read_u32
(
dev
->
of_node
,
"vf50-ts-min-pressure"
,
&
touchdev
->
min_pressure
);
if
(
error
)
return
error
;
input
=
devm_input_allocate_device
(
dev
);
if
(
!
input
)
{
dev_err
(
dev
,
"Failed to allocate TS input device
\n
"
);
return
-
ENOMEM
;
}
platform_set_drvdata
(
pdev
,
touchdev
);
input
->
name
=
DRIVER_NAME
;
input
->
id
.
bustype
=
BUS_HOST
;
input
->
dev
.
parent
=
dev
;
input
->
open
=
vf50_ts_open
;
input
->
close
=
vf50_ts_close
;
input_set_capability
(
input
,
EV_KEY
,
BTN_TOUCH
);
input_set_abs_params
(
input
,
ABS_X
,
0
,
VF_ADC_MAX
,
0
,
0
);
input_set_abs_params
(
input
,
ABS_Y
,
0
,
VF_ADC_MAX
,
0
,
0
);
input_set_abs_params
(
input
,
ABS_PRESSURE
,
0
,
VF_ADC_MAX
,
0
,
0
);
touchdev
->
ts_input
=
input
;
input_set_drvdata
(
input
,
touchdev
);
error
=
input_register_device
(
input
);
if
(
error
)
{
dev_err
(
dev
,
"Failed to register input device
\n
"
);
return
error
;
}
error
=
vf50_ts_get_gpiod
(
dev
,
&
touchdev
->
gpio_xp
,
"xp"
,
GPIOD_OUT_LOW
);
if
(
error
)
return
error
;
error
=
vf50_ts_get_gpiod
(
dev
,
&
touchdev
->
gpio_xm
,
"xm"
,
GPIOD_OUT_LOW
);
if
(
error
)
return
error
;
error
=
vf50_ts_get_gpiod
(
dev
,
&
touchdev
->
gpio_yp
,
"yp"
,
GPIOD_OUT_LOW
);
if
(
error
)
return
error
;
error
=
vf50_ts_get_gpiod
(
dev
,
&
touchdev
->
gpio_ym
,
"ym"
,
GPIOD_OUT_LOW
);
if
(
error
)
return
error
;
touchdev
->
pen_irq
=
platform_get_irq
(
pdev
,
0
);
if
(
touchdev
->
pen_irq
<
0
)
return
touchdev
->
pen_irq
;
error
=
devm_request_threaded_irq
(
dev
,
touchdev
->
pen_irq
,
NULL
,
vf50_ts_irq_bh
,
IRQF_ONESHOT
,
"vf50 touch"
,
touchdev
);
if
(
error
)
{
dev_err
(
dev
,
"Failed to request IRQ %d: %d
\n
"
,
touchdev
->
pen_irq
,
error
);
return
error
;
}
return
0
;
}
static
const
struct
of_device_id
vf50_touch_of_match
[]
=
{
{
.
compatible
=
"toradex,vf50-touchscreen"
,
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
vf50_touch_of_match
);
static
struct
platform_driver
vf50_touch_driver
=
{
.
driver
=
{
.
name
=
"toradex,vf50_touchctrl"
,
.
of_match_table
=
vf50_touch_of_match
,
},
.
probe
=
vf50_ts_probe
,
};
module_platform_driver
(
vf50_touch_driver
);
MODULE_AUTHOR
(
"Sanchayan Maity"
);
MODULE_DESCRIPTION
(
"Colibri VF50 Touchscreen driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_VERSION
(
DRV_VERSION
);
drivers/input/touchscreen/cyttsp4_i2c.c
View file @
53431d0a
...
...
@@ -86,4 +86,3 @@ module_i2c_driver(cyttsp4_i2c_driver);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"Cypress TrueTouch(R) Standard Product (TTSP) I2C driver"
);
MODULE_AUTHOR
(
"Cypress"
);
MODULE_ALIAS
(
"i2c:cyttsp4"
);
drivers/input/touchscreen/cyttsp_i2c.c
View file @
53431d0a
...
...
@@ -86,4 +86,3 @@ module_i2c_driver(cyttsp_i2c_driver);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"Cypress TrueTouch(R) Standard Product (TTSP) I2C driver"
);
MODULE_AUTHOR
(
"Cypress"
);
MODULE_ALIAS
(
"i2c:cyttsp"
);
drivers/input/touchscreen/elants_i2c.c
View file @
53431d0a
...
...
@@ -102,7 +102,7 @@
#define ELAN_FW_PAGESIZE 132
/* calibration timeout definition */
#define ELAN_CALI_TIMEOUT_MSEC 1
0
000
#define ELAN_CALI_TIMEOUT_MSEC 1
2
000
#define ELAN_POWERON_DELAY_USEC 500
#define ELAN_RESET_DELAY_MSEC 20
...
...
drivers/input/touchscreen/imx6ul_tsc.c
0 → 100644
View file @
53431d0a
/*
* Freescale i.MX6UL touchscreen controller driver
*
* Copyright (C) 2015 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
/* ADC configuration registers field define */
#define ADC_AIEN (0x1 << 7)
#define ADC_CONV_DISABLE 0x1F
#define ADC_CAL (0x1 << 7)
#define ADC_CALF 0x2
#define ADC_12BIT_MODE (0x2 << 2)
#define ADC_IPG_CLK 0x00
#define ADC_CLK_DIV_8 (0x03 << 5)
#define ADC_SHORT_SAMPLE_MODE (0x0 << 4)
#define ADC_HARDWARE_TRIGGER (0x1 << 13)
#define SELECT_CHANNEL_4 0x04
#define SELECT_CHANNEL_1 0x01
#define DISABLE_CONVERSION_INT (0x0 << 7)
/* ADC registers */
#define REG_ADC_HC0 0x00
#define REG_ADC_HC1 0x04
#define REG_ADC_HC2 0x08
#define REG_ADC_HC3 0x0C
#define REG_ADC_HC4 0x10
#define REG_ADC_HS 0x14
#define REG_ADC_R0 0x18
#define REG_ADC_CFG 0x2C
#define REG_ADC_GC 0x30
#define REG_ADC_GS 0x34
#define ADC_TIMEOUT msecs_to_jiffies(100)
/* TSC registers */
#define REG_TSC_BASIC_SETING 0x00
#define REG_TSC_PRE_CHARGE_TIME 0x10
#define REG_TSC_FLOW_CONTROL 0x20
#define REG_TSC_MEASURE_VALUE 0x30
#define REG_TSC_INT_EN 0x40
#define REG_TSC_INT_SIG_EN 0x50
#define REG_TSC_INT_STATUS 0x60
#define REG_TSC_DEBUG_MODE 0x70
#define REG_TSC_DEBUG_MODE2 0x80
/* TSC configuration registers field define */
#define DETECT_4_WIRE_MODE (0x0 << 4)
#define AUTO_MEASURE 0x1
#define MEASURE_SIGNAL 0x1
#define DETECT_SIGNAL (0x1 << 4)
#define VALID_SIGNAL (0x1 << 8)
#define MEASURE_INT_EN 0x1
#define MEASURE_SIG_EN 0x1
#define VALID_SIG_EN (0x1 << 8)
#define DE_GLITCH_2 (0x2 << 29)
#define START_SENSE (0x1 << 12)
#define TSC_DISABLE (0x1 << 16)
#define DETECT_MODE 0x2
struct
imx6ul_tsc
{
struct
device
*
dev
;
struct
input_dev
*
input
;
void
__iomem
*
tsc_regs
;
void
__iomem
*
adc_regs
;
struct
clk
*
tsc_clk
;
struct
clk
*
adc_clk
;
struct
gpio_desc
*
xnur_gpio
;
int
measure_delay_time
;
int
pre_charge_time
;
struct
completion
completion
;
};
/*
* TSC module need ADC to get the measure value. So
* before config TSC, we should initialize ADC module.
*/
static
void
imx6ul_adc_init
(
struct
imx6ul_tsc
*
tsc
)
{
int
adc_hc
=
0
;
int
adc_gc
;
int
adc_gs
;
int
adc_cfg
;
int
timeout
;
reinit_completion
(
&
tsc
->
completion
);
adc_cfg
=
readl
(
tsc
->
adc_regs
+
REG_ADC_CFG
);
adc_cfg
|=
ADC_12BIT_MODE
|
ADC_IPG_CLK
;
adc_cfg
|=
ADC_CLK_DIV_8
|
ADC_SHORT_SAMPLE_MODE
;
adc_cfg
&=
~
ADC_HARDWARE_TRIGGER
;
writel
(
adc_cfg
,
tsc
->
adc_regs
+
REG_ADC_CFG
);
/* enable calibration interrupt */
adc_hc
|=
ADC_AIEN
;
adc_hc
|=
ADC_CONV_DISABLE
;
writel
(
adc_hc
,
tsc
->
adc_regs
+
REG_ADC_HC0
);
/* start ADC calibration */
adc_gc
=
readl
(
tsc
->
adc_regs
+
REG_ADC_GC
);
adc_gc
|=
ADC_CAL
;
writel
(
adc_gc
,
tsc
->
adc_regs
+
REG_ADC_GC
);
timeout
=
wait_for_completion_timeout
(
&
tsc
->
completion
,
ADC_TIMEOUT
);
if
(
timeout
==
0
)
dev_err
(
tsc
->
dev
,
"Timeout for adc calibration
\n
"
);
adc_gs
=
readl
(
tsc
->
adc_regs
+
REG_ADC_GS
);
if
(
adc_gs
&
ADC_CALF
)
dev_err
(
tsc
->
dev
,
"ADC calibration failed
\n
"
);
/* TSC need the ADC work in hardware trigger */
adc_cfg
=
readl
(
tsc
->
adc_regs
+
REG_ADC_CFG
);
adc_cfg
|=
ADC_HARDWARE_TRIGGER
;
writel
(
adc_cfg
,
tsc
->
adc_regs
+
REG_ADC_CFG
);
}
/*
* This is a TSC workaround. Currently TSC misconnect two
* ADC channels, this function remap channel configure for
* hardware trigger.
*/
static
void
imx6ul_tsc_channel_config
(
struct
imx6ul_tsc
*
tsc
)
{
int
adc_hc0
,
adc_hc1
,
adc_hc2
,
adc_hc3
,
adc_hc4
;
adc_hc0
=
DISABLE_CONVERSION_INT
;
writel
(
adc_hc0
,
tsc
->
adc_regs
+
REG_ADC_HC0
);
adc_hc1
=
DISABLE_CONVERSION_INT
|
SELECT_CHANNEL_4
;
writel
(
adc_hc1
,
tsc
->
adc_regs
+
REG_ADC_HC1
);
adc_hc2
=
DISABLE_CONVERSION_INT
;
writel
(
adc_hc2
,
tsc
->
adc_regs
+
REG_ADC_HC2
);
adc_hc3
=
DISABLE_CONVERSION_INT
|
SELECT_CHANNEL_1
;
writel
(
adc_hc3
,
tsc
->
adc_regs
+
REG_ADC_HC3
);
adc_hc4
=
DISABLE_CONVERSION_INT
;
writel
(
adc_hc4
,
tsc
->
adc_regs
+
REG_ADC_HC4
);
}
/*
* TSC setting, confige the pre-charge time and measure delay time.
* different touch screen may need different pre-charge time and
* measure delay time.
*/
static
void
imx6ul_tsc_set
(
struct
imx6ul_tsc
*
tsc
)
{
int
basic_setting
=
0
;
int
start
;
basic_setting
|=
tsc
->
measure_delay_time
<<
8
;
basic_setting
|=
DETECT_4_WIRE_MODE
|
AUTO_MEASURE
;
writel
(
basic_setting
,
tsc
->
tsc_regs
+
REG_TSC_BASIC_SETING
);
writel
(
DE_GLITCH_2
,
tsc
->
tsc_regs
+
REG_TSC_DEBUG_MODE2
);
writel
(
tsc
->
pre_charge_time
,
tsc
->
tsc_regs
+
REG_TSC_PRE_CHARGE_TIME
);
writel
(
MEASURE_INT_EN
,
tsc
->
tsc_regs
+
REG_TSC_INT_EN
);
writel
(
MEASURE_SIG_EN
|
VALID_SIG_EN
,
tsc
->
tsc_regs
+
REG_TSC_INT_SIG_EN
);
/* start sense detection */
start
=
readl
(
tsc
->
tsc_regs
+
REG_TSC_FLOW_CONTROL
);
start
|=
START_SENSE
;
start
&=
~
TSC_DISABLE
;
writel
(
start
,
tsc
->
tsc_regs
+
REG_TSC_FLOW_CONTROL
);
}
static
void
imx6ul_tsc_init
(
struct
imx6ul_tsc
*
tsc
)
{
imx6ul_adc_init
(
tsc
);
imx6ul_tsc_channel_config
(
tsc
);
imx6ul_tsc_set
(
tsc
);
}
static
void
imx6ul_tsc_disable
(
struct
imx6ul_tsc
*
tsc
)
{
int
tsc_flow
;
int
adc_cfg
;
/* TSC controller enters to idle status */
tsc_flow
=
readl
(
tsc
->
tsc_regs
+
REG_TSC_FLOW_CONTROL
);
tsc_flow
|=
TSC_DISABLE
;
writel
(
tsc_flow
,
tsc
->
tsc_regs
+
REG_TSC_FLOW_CONTROL
);
/* ADC controller enters to stop mode */
adc_cfg
=
readl
(
tsc
->
adc_regs
+
REG_ADC_HC0
);
adc_cfg
|=
ADC_CONV_DISABLE
;
writel
(
adc_cfg
,
tsc
->
adc_regs
+
REG_ADC_HC0
);
}
/* Delay some time (max 2ms), wait the pre-charge done. */
static
bool
tsc_wait_detect_mode
(
struct
imx6ul_tsc
*
tsc
)
{
unsigned
long
timeout
=
jiffies
+
msecs_to_jiffies
(
2
);
int
state_machine
;
int
debug_mode2
;
do
{
if
(
time_after
(
jiffies
,
timeout
))
return
false
;
usleep_range
(
200
,
400
);
debug_mode2
=
readl
(
tsc
->
tsc_regs
+
REG_TSC_DEBUG_MODE2
);
state_machine
=
(
debug_mode2
>>
20
)
&
0x7
;
}
while
(
state_machine
!=
DETECT_MODE
);
usleep_range
(
200
,
400
);
return
true
;
}
static
irqreturn_t
tsc_irq_fn
(
int
irq
,
void
*
dev_id
)
{
struct
imx6ul_tsc
*
tsc
=
dev_id
;
int
status
;
int
value
;
int
x
,
y
;
int
start
;
status
=
readl
(
tsc
->
tsc_regs
+
REG_TSC_INT_STATUS
);
/* write 1 to clear the bit measure-signal */
writel
(
MEASURE_SIGNAL
|
DETECT_SIGNAL
,
tsc
->
tsc_regs
+
REG_TSC_INT_STATUS
);
/* It's a HW self-clean bit. Set this bit and start sense detection */
start
=
readl
(
tsc
->
tsc_regs
+
REG_TSC_FLOW_CONTROL
);
start
|=
START_SENSE
;
writel
(
start
,
tsc
->
tsc_regs
+
REG_TSC_FLOW_CONTROL
);
if
(
status
&
MEASURE_SIGNAL
)
{
value
=
readl
(
tsc
->
tsc_regs
+
REG_TSC_MEASURE_VALUE
);
x
=
(
value
>>
16
)
&
0x0fff
;
y
=
value
&
0x0fff
;
/*
* In detect mode, we can get the xnur gpio value,
* otherwise assume contact is stiull active.
*/
if
(
!
tsc_wait_detect_mode
(
tsc
)
||
gpiod_get_value_cansleep
(
tsc
->
xnur_gpio
))
{
input_report_key
(
tsc
->
input
,
BTN_TOUCH
,
1
);
input_report_abs
(
tsc
->
input
,
ABS_X
,
x
);
input_report_abs
(
tsc
->
input
,
ABS_Y
,
y
);
}
else
{
input_report_key
(
tsc
->
input
,
BTN_TOUCH
,
0
);
}
input_sync
(
tsc
->
input
);
}
return
IRQ_HANDLED
;
}
static
irqreturn_t
adc_irq_fn
(
int
irq
,
void
*
dev_id
)
{
struct
imx6ul_tsc
*
tsc
=
dev_id
;
int
coco
;
int
value
;
coco
=
readl
(
tsc
->
adc_regs
+
REG_ADC_HS
);
if
(
coco
&
0x01
)
{
value
=
readl
(
tsc
->
adc_regs
+
REG_ADC_R0
);
complete
(
&
tsc
->
completion
);
}
return
IRQ_HANDLED
;
}
static
int
imx6ul_tsc_open
(
struct
input_dev
*
input_dev
)
{
struct
imx6ul_tsc
*
tsc
=
input_get_drvdata
(
input_dev
);
int
err
;
err
=
clk_prepare_enable
(
tsc
->
adc_clk
);
if
(
err
)
{
dev_err
(
tsc
->
dev
,
"Could not prepare or enable the adc clock: %d
\n
"
,
err
);
return
err
;
}
err
=
clk_prepare_enable
(
tsc
->
tsc_clk
);
if
(
err
)
{
dev_err
(
tsc
->
dev
,
"Could not prepare or enable the tsc clock: %d
\n
"
,
err
);
clk_disable_unprepare
(
tsc
->
adc_clk
);
return
err
;
}
imx6ul_tsc_init
(
tsc
);
return
0
;
}
static
void
imx6ul_tsc_close
(
struct
input_dev
*
input_dev
)
{
struct
imx6ul_tsc
*
tsc
=
input_get_drvdata
(
input_dev
);
imx6ul_tsc_disable
(
tsc
);
clk_disable_unprepare
(
tsc
->
tsc_clk
);
clk_disable_unprepare
(
tsc
->
adc_clk
);
}
static
int
imx6ul_tsc_probe
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
imx6ul_tsc
*
tsc
;
struct
input_dev
*
input_dev
;
struct
resource
*
tsc_mem
;
struct
resource
*
adc_mem
;
int
err
;
int
tsc_irq
;
int
adc_irq
;
tsc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
struct
imx6ul_tsc
),
GFP_KERNEL
);
if
(
!
tsc
)
return
-
ENOMEM
;
input_dev
=
devm_input_allocate_device
(
&
pdev
->
dev
);
if
(
!
input_dev
)
return
-
ENOMEM
;
input_dev
->
name
=
"iMX6UL TouchScreen Controller"
;
input_dev
->
id
.
bustype
=
BUS_HOST
;
input_dev
->
open
=
imx6ul_tsc_open
;
input_dev
->
close
=
imx6ul_tsc_close
;
input_set_capability
(
input_dev
,
EV_KEY
,
BTN_TOUCH
);
input_set_abs_params
(
input_dev
,
ABS_X
,
0
,
0xFFF
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_Y
,
0
,
0xFFF
,
0
,
0
);
input_set_drvdata
(
input_dev
,
tsc
);
tsc
->
dev
=
&
pdev
->
dev
;
tsc
->
input
=
input_dev
;
init_completion
(
&
tsc
->
completion
);
tsc
->
xnur_gpio
=
devm_gpiod_get
(
&
pdev
->
dev
,
"xnur"
,
GPIOD_IN
);
if
(
IS_ERR
(
tsc
->
xnur_gpio
))
{
err
=
PTR_ERR
(
tsc
->
xnur_gpio
);
dev_err
(
&
pdev
->
dev
,
"failed to request GPIO tsc_X- (xnur): %d
\n
"
,
err
);
return
err
;
}
tsc_mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
tsc
->
tsc_regs
=
devm_ioremap_resource
(
&
pdev
->
dev
,
tsc_mem
);
if
(
IS_ERR
(
tsc
->
tsc_regs
))
{
err
=
PTR_ERR
(
tsc
->
tsc_regs
);
dev_err
(
&
pdev
->
dev
,
"failed to remap tsc memory: %d
\n
"
,
err
);
return
err
;
}
adc_mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
1
);
tsc
->
adc_regs
=
devm_ioremap_resource
(
&
pdev
->
dev
,
adc_mem
);
if
(
IS_ERR
(
tsc
->
adc_regs
))
{
err
=
PTR_ERR
(
tsc
->
adc_regs
);
dev_err
(
&
pdev
->
dev
,
"failed to remap adc memory: %d
\n
"
,
err
);
return
err
;
}
tsc
->
tsc_clk
=
devm_clk_get
(
&
pdev
->
dev
,
"tsc"
);
if
(
IS_ERR
(
tsc
->
tsc_clk
))
{
err
=
PTR_ERR
(
tsc
->
tsc_clk
);
dev_err
(
&
pdev
->
dev
,
"failed getting tsc clock: %d
\n
"
,
err
);
return
err
;
}
tsc
->
adc_clk
=
devm_clk_get
(
&
pdev
->
dev
,
"adc"
);
if
(
IS_ERR
(
tsc
->
adc_clk
))
{
err
=
PTR_ERR
(
tsc
->
adc_clk
);
dev_err
(
&
pdev
->
dev
,
"failed getting adc clock: %d
\n
"
,
err
);
return
err
;
}
tsc_irq
=
platform_get_irq
(
pdev
,
0
);
if
(
tsc_irq
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"no tsc irq resource?
\n
"
);
return
tsc_irq
;
}
adc_irq
=
platform_get_irq
(
pdev
,
1
);
if
(
adc_irq
<=
0
)
{
dev_err
(
&
pdev
->
dev
,
"no adc irq resource?
\n
"
);
return
adc_irq
;
}
err
=
devm_request_threaded_irq
(
tsc
->
dev
,
tsc_irq
,
NULL
,
tsc_irq_fn
,
IRQF_ONESHOT
,
dev_name
(
&
pdev
->
dev
),
tsc
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"failed requesting tsc irq %d: %d
\n
"
,
tsc_irq
,
err
);
return
err
;
}
err
=
devm_request_irq
(
tsc
->
dev
,
adc_irq
,
adc_irq_fn
,
0
,
dev_name
(
&
pdev
->
dev
),
tsc
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"failed requesting adc irq %d: %d
\n
"
,
adc_irq
,
err
);
return
err
;
}
err
=
of_property_read_u32
(
np
,
"measure-delay-time"
,
&
tsc
->
measure_delay_time
);
if
(
err
)
tsc
->
measure_delay_time
=
0xffff
;
err
=
of_property_read_u32
(
np
,
"pre-charge-time"
,
&
tsc
->
pre_charge_time
);
if
(
err
)
tsc
->
pre_charge_time
=
0xfff
;
err
=
input_register_device
(
tsc
->
input
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register input device: %d
\n
"
,
err
);
return
err
;
}
platform_set_drvdata
(
pdev
,
tsc
);
return
0
;
}
static
int
__maybe_unused
imx6ul_tsc_suspend
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
imx6ul_tsc
*
tsc
=
platform_get_drvdata
(
pdev
);
struct
input_dev
*
input_dev
=
tsc
->
input
;
mutex_lock
(
&
input_dev
->
mutex
);
if
(
input_dev
->
users
)
{
imx6ul_tsc_disable
(
tsc
);
clk_disable_unprepare
(
tsc
->
tsc_clk
);
clk_disable_unprepare
(
tsc
->
adc_clk
);
}
mutex_unlock
(
&
input_dev
->
mutex
);
return
0
;
}
static
int
__maybe_unused
imx6ul_tsc_resume
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
imx6ul_tsc
*
tsc
=
platform_get_drvdata
(
pdev
);
struct
input_dev
*
input_dev
=
tsc
->
input
;
int
retval
=
0
;
mutex_lock
(
&
input_dev
->
mutex
);
if
(
input_dev
->
users
)
{
retval
=
clk_prepare_enable
(
tsc
->
adc_clk
);
if
(
retval
)
goto
out
;
retval
=
clk_prepare_enable
(
tsc
->
tsc_clk
);
if
(
retval
)
{
clk_disable_unprepare
(
tsc
->
adc_clk
);
goto
out
;
}
imx6ul_tsc_init
(
tsc
);
}
out:
mutex_unlock
(
&
input_dev
->
mutex
);
return
retval
;
}
static
SIMPLE_DEV_PM_OPS
(
imx6ul_tsc_pm_ops
,
imx6ul_tsc_suspend
,
imx6ul_tsc_resume
);
static
const
struct
of_device_id
imx6ul_tsc_match
[]
=
{
{
.
compatible
=
"fsl,imx6ul-tsc"
,
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
of
,
imx6ul_tsc_match
);
static
struct
platform_driver
imx6ul_tsc_driver
=
{
.
driver
=
{
.
name
=
"imx6ul-tsc"
,
.
of_match_table
=
imx6ul_tsc_match
,
.
pm
=
&
imx6ul_tsc_pm_ops
,
},
.
probe
=
imx6ul_tsc_probe
,
};
module_platform_driver
(
imx6ul_tsc_driver
);
MODULE_AUTHOR
(
"Haibo Chen <haibo.chen@freescale.com>"
);
MODULE_DESCRIPTION
(
"Freescale i.MX6UL Touchscreen controller driver"
);
MODULE_LICENSE
(
"GPL v2"
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment