Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
53431d0a
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
53431d0a
编写于
9月 11, 2015
作者:
D
Dmitry Torokhov
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'next' into for-linus
Prepare second round of input updates for 4.3 merge window.
上级
01b944fe
ade9c1a4
变更
17
隐藏空白更改
内联
并排
Showing
17 changed file
with
1019 addition
and
15 deletion
+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
未找到文件。
Documentation/devicetree/bindings/input/touchscreen/colibri-vf50-ts.txt
0 → 100644
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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"
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录