Merge f78e9de80f ("Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input") into android-mainline

Steps on the way to 5.16-rc1

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I78a89c32422b0b415dff9682ec10f464846c2c66
This commit is contained in:
Greg Kroah-Hartman 2021-11-16 11:13:29 +01:00
commit 64d2f9bc97
463 changed files with 8264 additions and 6888 deletions

View file

@ -61,8 +61,9 @@ arg3:
``pid`` of the task for which the operation applies.
arg4:
``pid_type`` for which the operation applies. It is of type ``enum pid_type``.
For example, if arg4 is ``PIDTYPE_TGID``, then the operation of this command
``pid_type`` for which the operation applies. It is one of
``PR_SCHED_CORE_SCOPE_``-prefixed macro constants. For example, if arg4
is ``PR_SCHED_CORE_SCOPE_THREAD_GROUP``, then the operation of this command
will be performed for all tasks in the task group of ``pid``.
arg5:

View file

@ -3257,6 +3257,19 @@
driver. A non-zero value sets the minimum interval
in seconds between layoutstats transmissions.
nfsd.inter_copy_offload_enable =
[NFSv4.2] When set to 1, the server will support
server-to-server copies for which this server is
the destination of the copy.
nfsd.nfsd4_ssc_umount_timeout =
[NFSv4.2] When used as the destination of a
server-to-server copy, knfsd temporarily mounts
the source server. It caches the mount in case
it will be needed again, and discards it if not
used for the number of milliseconds specified by
this parameter.
nfsd.nfs4_disable_idmapping=
[NFSv4] When set to the default of '1', the NFSv4
server will return only numeric uids and gids to
@ -3264,6 +3277,7 @@
and gids from such clients. This is intended to ease
migration from NFSv2/v3.
nmi_backtrace.backtrace_idle [KNL]
Dump stacks even of idle CPUs in response to an
NMI stack-backtrace request.

View file

@ -0,0 +1,61 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/cypress-sf.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cypress StreetFighter touchkey controller
maintainers:
- Yassine Oudjana <y.oudjana@protonmail.com>
allOf:
- $ref: input.yaml#
properties:
compatible:
const: cypress,sf3155
reg:
maxItems: 1
interrupts:
maxItems: 1
avdd-supply:
description: Regulator for AVDD analog voltage
vdd-supply:
description: Regulator for VDD digital voltage
linux,keycodes:
minItems: 1
maxItems: 8
required:
- compatible
- reg
- interrupts
- avdd-supply
- vdd-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
touchkey@28 {
compatible = "cypress,sf3155";
reg = <0x28>;
interrupt-parent = <&msmgpio>;
interrupts = <77 IRQ_TYPE_EDGE_FALLING>;
avdd-supply = <&vreg_l6a_1p8>;
vdd-supply = <&vdd_3v2_tp>;
linux,keycodes = <KEY_BACK KEY_MENU>;
};
};

View file

@ -19,6 +19,7 @@ properties:
- microchip,cap1106
- microchip,cap1126
- microchip,cap1188
- microchip,cap1206
reg:
maxItems: 1

View file

@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/mstar,msc313-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mstar MSC313e RTC Device Tree Bindings
allOf:
- $ref: "rtc.yaml#"
maintainers:
- Daniel Palmer <daniel@0x0f.com>
- Romain Perier <romain.perier@gmail.com>
properties:
compatible:
enum:
- mstar,msc313-rtc
reg:
maxItems: 1
interrupts:
maxItems: 1
start-year: true
clocks:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
rtc@2400 {
compatible = "mstar,msc313-rtc";
reg = <0x2400 0x40>;
clocks = <&xtal_div2>;
interrupts-extended = <&intc_irq GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
};
...

View file

@ -13,10 +13,19 @@ Optional property:
expressed in femto Farad (fF). Valid values are 7000 and 12500.
Default value (if no value is specified) is 7000fF.
Optional child node:
- clock: Provide this if the square wave pin is used as boot-enabled fixed clock.
Example:
pcf85063: rtc@51 {
compatible = "nxp,pcf85063";
reg = <0x51>;
quartz-load-femtofarads = <12500>;
clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
};
};

View file

@ -11,3 +11,4 @@ NFS
rpc-server-gss
nfs41-server
knfsd-stats
reexport

View file

@ -0,0 +1,113 @@
Reexporting NFS filesystems
===========================
Overview
--------
It is possible to reexport an NFS filesystem over NFS. However, this
feature comes with a number of limitations. Before trying it, we
recommend some careful research to determine whether it will work for
your purposes.
A discussion of current known limitations follows.
"fsid=" required, crossmnt broken
---------------------------------
We require the "fsid=" export option on any reexport of an NFS
filesystem. You can use "uuidgen -r" to generate a unique argument.
The "crossmnt" export does not propagate "fsid=", so it will not allow
traversing into further nfs filesystems; if you wish to export nfs
filesystems mounted under the exported filesystem, you'll need to export
them explicitly, assigning each its own unique "fsid= option.
Reboot recovery
---------------
The NFS protocol's normal reboot recovery mechanisms don't work for the
case when the reexport server reboots. Clients will lose any locks
they held before the reboot, and further IO will result in errors.
Closing and reopening files should clear the errors.
Filehandle limits
-----------------
If the original server uses an X byte filehandle for a given object, the
reexport server's filehandle for the reexported object will be X+22
bytes, rounded up to the nearest multiple of four bytes.
The result must fit into the RFC-mandated filehandle size limits:
+-------+-----------+
| NFSv2 | 32 bytes |
+-------+-----------+
| NFSv3 | 64 bytes |
+-------+-----------+
| NFSv4 | 128 bytes |
+-------+-----------+
So, for example, you will only be able to reexport a filesystem over
NFSv2 if the original server gives you filehandles that fit in 10
bytes--which is unlikely.
In general there's no way to know the maximum filehandle size given out
by an NFS server without asking the server vendor.
But the following table gives a few examples. The first column is the
typical length of the filehandle from a Linux server exporting the given
filesystem, the second is the length after that nfs export is reexported
by another Linux host:
+--------+-------------------+----------------+
| | filehandle length | after reexport |
+========+===================+================+
| ext4: | 28 bytes | 52 bytes |
+--------+-------------------+----------------+
| xfs: | 32 bytes | 56 bytes |
+--------+-------------------+----------------+
| btrfs: | 40 bytes | 64 bytes |
+--------+-------------------+----------------+
All will therefore fit in an NFSv3 or NFSv4 filehandle after reexport,
but none are reexportable over NFSv2.
Linux server filehandles are a bit more complicated than this, though;
for example:
- The (non-default) "subtreecheck" export option generally
requires another 4 to 8 bytes in the filehandle.
- If you export a subdirectory of a filesystem (instead of
exporting the filesystem root), that also usually adds 4 to 8
bytes.
- If you export over NFSv2, knfsd usually uses a shorter
filesystem identifier that saves 8 bytes.
- The root directory of an export uses a filehandle that is
shorter.
As you can see, the 128-byte NFSv4 filehandle is large enough that
you're unlikely to have trouble using NFSv4 to reexport any filesystem
exported from a Linux server. In general, if the original server is
something that also supports NFSv3, you're *probably* OK. Re-exporting
over NFSv3 may be dicier, and reexporting over NFSv2 will probably
never work.
For more details of Linux filehandle structure, the best reference is
the source code and comments; see in particular:
- include/linux/exportfs.h:enum fid_type
- include/uapi/linux/nfsd/nfsfh.h:struct nfs_fhbase_new
- fs/nfsd/nfsfh.c:set_version_and_fsid_type
- fs/nfs/export.c:nfs_encode_fh
Open DENY bits ignored
----------------------
NFS since NFSv4 supports ALLOW and DENY bits taken from Windows, which
allow you, for example, to open a file in a mode which forbids other
read opens or write opens. The Linux client doesn't use them, and the
server's support has always been incomplete: they are enforced only
against other NFS users, not against processes accessing the exported
filesystem locally. A reexport server will also not pass them along to
the original server, so they will not be enforced between clients of
different reexport servers.

View file

@ -1004,13 +1004,11 @@ udp_l3mdev_accept - BOOLEAN
udp_mem - vector of 3 INTEGERs: min, pressure, max
Number of pages allowed for queueing by all UDP sockets.
min: Below this number of pages UDP is not bothered about its
memory appetite. When amount of memory allocated by UDP exceeds
this number, UDP starts to moderate memory usage.
min: Number of pages allowed for queueing by all UDP sockets.
pressure: This value was introduced to follow format of tcp_mem.
max: Number of pages allowed for queueing by all UDP sockets.
max: This value was introduced to follow format of tcp_mem.
Default is calculated at boot time from amount of available memory.

View file

@ -15,10 +15,7 @@ For security module support, three SCTP specific hooks have been implemented::
security_sctp_assoc_request()
security_sctp_bind_connect()
security_sctp_sk_clone()
Also the following security hook has been utilised::
security_inet_conn_established()
security_sctp_assoc_established()
The usage of these hooks are described below with the SELinux implementation
described in the `SCTP SELinux Support`_ chapter.
@ -26,11 +23,11 @@ described in the `SCTP SELinux Support`_ chapter.
security_sctp_assoc_request()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Passes the ``@ep`` and ``@chunk->skb`` of the association INIT packet to the
Passes the ``@asoc`` and ``@chunk->skb`` of the association INIT packet to the
security module. Returns 0 on success, error on failure.
::
@ep - pointer to sctp endpoint structure.
@asoc - pointer to sctp association structure.
@skb - pointer to skbuff of association packet.
@ -117,16 +114,17 @@ Called whenever a new socket is created by **accept**\(2)
calls **sctp_peeloff**\(3).
::
@ep - pointer to current sctp endpoint structure.
@asoc - pointer to current sctp association structure.
@sk - pointer to current sock structure.
@sk - pointer to new sock structure.
@newsk - pointer to new sock structure.
security_inet_conn_established()
security_sctp_assoc_established()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Called when a COOKIE ACK is received::
Called when a COOKIE ACK is received, and the peer secid will be
saved into ``@asoc->peer_secid`` for client::
@sk - pointer to sock structure.
@asoc - pointer to sctp association structure.
@skb - pointer to skbuff of the COOKIE ACK packet.
@ -134,7 +132,7 @@ Security Hooks used for Association Establishment
-------------------------------------------------
The following diagram shows the use of ``security_sctp_bind_connect()``,
``security_sctp_assoc_request()``, ``security_inet_conn_established()`` when
``security_sctp_assoc_request()``, ``security_sctp_assoc_established()`` when
establishing an association.
::
@ -151,9 +149,9 @@ establishing an association.
INIT --------------------------------------------->
sctp_sf_do_5_1B_init()
Respond to an INIT chunk.
SCTP peer endpoint "A" is
asking for an association. Call
security_sctp_assoc_request()
SCTP peer endpoint "A" is asking
for a temporary association.
Call security_sctp_assoc_request()
to set the peer label if first
association.
If not first association, check
@ -163,13 +161,16 @@ establishing an association.
| discard the packet.
|
COOKIE ECHO ------------------------------------------>
|
|
|
sctp_sf_do_5_1D_ce()
Respond to an COOKIE ECHO chunk.
Confirm the cookie and create a
permanent association.
Call security_sctp_assoc_request() to
do the same as for INIT chunk Response.
<------------------------------------------- COOKIE ACK
| |
sctp_sf_do_5_1E_ca |
Call security_inet_conn_established() |
Call security_sctp_assoc_established() |
to set the peer label. |
| |
| If SCTP_SOCKET_TCP or peeled off
@ -195,27 +196,27 @@ hooks with the SELinux specifics expanded below::
security_sctp_assoc_request()
security_sctp_bind_connect()
security_sctp_sk_clone()
security_inet_conn_established()
security_sctp_assoc_established()
security_sctp_assoc_request()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Passes the ``@ep`` and ``@chunk->skb`` of the association INIT packet to the
Passes the ``@asoc`` and ``@chunk->skb`` of the association INIT packet to the
security module. Returns 0 on success, error on failure.
::
@ep - pointer to sctp endpoint structure.
@asoc - pointer to sctp association structure.
@skb - pointer to skbuff of association packet.
The security module performs the following operations:
IF this is the first association on ``@ep->base.sk``, then set the peer
IF this is the first association on ``@asoc->base.sk``, then set the peer
sid to that in ``@skb``. This will ensure there is only one peer sid
assigned to ``@ep->base.sk`` that may support multiple associations.
assigned to ``@asoc->base.sk`` that may support multiple associations.
ELSE validate the ``@ep->base.sk peer_sid`` against the ``@skb peer sid``
ELSE validate the ``@asoc->base.sk peer_sid`` against the ``@skb peer sid``
to determine whether the association should be allowed or denied.
Set the sctp ``@ep sid`` to socket's sid (from ``ep->base.sk``) with
Set the sctp ``@asoc sid`` to socket's sid (from ``asoc->base.sk``) with
MLS portion taken from ``@skb peer sid``. This will be used by SCTP
TCP style sockets and peeled off connections as they cause a new socket
to be generated.
@ -259,21 +260,21 @@ security_sctp_sk_clone()
Called whenever a new socket is created by **accept**\(2) (i.e. a TCP style
socket) or when a socket is 'peeled off' e.g userspace calls
**sctp_peeloff**\(3). ``security_sctp_sk_clone()`` will set the new
sockets sid and peer sid to that contained in the ``@ep sid`` and
``@ep peer sid`` respectively.
sockets sid and peer sid to that contained in the ``@asoc sid`` and
``@asoc peer sid`` respectively.
::
@ep - pointer to current sctp endpoint structure.
@asoc - pointer to current sctp association structure.
@sk - pointer to current sock structure.
@sk - pointer to new sock structure.
@newsk - pointer to new sock structure.
security_inet_conn_established()
security_sctp_assoc_established()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Called when a COOKIE ACK is received where it sets the connection's peer sid
to that in ``@skb``::
@sk - pointer to sock structure.
@asoc - pointer to sctp association structure.
@skb - pointer to skbuff of the COOKIE ACK packet.

View file

@ -360,7 +360,7 @@ between device driver specific code and shared common code:
system memory page, locks the page with ``lock_page()``, and fills in the
``dst`` array entry with::
dst[i] = migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED;
dst[i] = migrate_pfn(page_to_pfn(dpage));
Now that the driver knows that this page is being migrated, it can
invalidate device private MMU mappings and copy device private memory

View file

@ -872,9 +872,10 @@ F: Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt
F: drivers/thermal/thermal_mmio.c
AMAZON ETHERNET DRIVERS
M: Netanel Belgazal <netanel@amazon.com>
M: Shay Agroskin <shayagr@amazon.com>
M: Arthur Kiyanovski <akiyano@amazon.com>
R: Guy Tzalik <gtzalik@amazon.com>
R: David Arinzon <darinzon@amazon.com>
R: Noam Dagan <ndagan@amazon.com>
R: Saeed Bishara <saeedb@amazon.com>
L: netdev@vger.kernel.org
S: Supported
@ -2282,6 +2283,7 @@ F: arch/arm/boot/dts/mstar-*
F: arch/arm/mach-mstar/
F: drivers/clk/mstar/
F: drivers/gpio/gpio-msc313.c
F: drivers/rtc/rtc-msc313.c
F: drivers/watchdog/msc313e_wdt.c
F: include/dt-bindings/clock/mstar-*
F: include/dt-bindings/gpio/msc313-gpio.h
@ -4457,7 +4459,7 @@ CHIPONE ICN8318 I2C TOUCHSCREEN DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-input@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt
F: Documentation/devicetree/bindings/input/touchscreen/chipone,icn8318.yaml
F: drivers/input/touchscreen/chipone_icn8318.c
CHIPONE ICN8505 I2C TOUCHSCREEN DRIVER
@ -5203,6 +5205,13 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/cy8ctma140.c
CYPRESS STREETFIGHTER TOUCHKEYS DRIVER
M: Yassine Oudjana <y.oudjana@protonmail.com>
L: linux-input@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/input/cypress-sf.yaml
F: drivers/input/keyboard/cypress-sf.c
CYTTSP TOUCHSCREEN DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-input@vger.kernel.org
@ -8061,9 +8070,10 @@ F: drivers/media/usb/go7007/
GOODIX TOUCHSCREEN
M: Bastien Nocera <hadess@hadess.net>
M: Hans de Goede <hdegoede@redhat.com>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/goodix.c
F: drivers/input/touchscreen/goodix*
GOOGLE ETHERNET DRIVERS
M: Jeroen de Borst <jeroendb@google.com>
@ -10805,11 +10815,6 @@ F: drivers/ata/
F: include/linux/ata.h
F: include/linux/libata.h
LIBLOCKDEP
M: Sasha Levin <alexander.levin@microsoft.com>
S: Maintained
F: tools/lib/lockdep/
LIBNVDIMM BLK: MMIO-APERTURE DRIVER
M: Dan Williams <dan.j.williams@intel.com>
M: Vishal Verma <vishal.l.verma@intel.com>

View file

@ -294,7 +294,7 @@ int elf_check_arch(const struct elf32_hdr *x)
eflags = x->e_flags;
if ((eflags & EF_ARC_OSABI_MSK) != EF_ARC_OSABI_CURRENT) {
pr_err("ABI mismatch - you need newer toolchain\n");
force_sigsegv(SIGSEGV);
force_fatal_sig(SIGSEGV);
return 0;
}

View file

@ -310,7 +310,7 @@ void __init kasan_init(void)
kasan_init_depth();
#if defined(CONFIG_KASAN_GENERIC)
/* CONFIG_KASAN_SW_TAGS also requires kasan_init_sw_tags(). */
pr_info("KernelAddressSanitizer initialized\n");
pr_info("KernelAddressSanitizer initialized (generic)\n");
#endif
}

View file

@ -53,17 +53,6 @@ config M68000
System-On-Chip devices (eg 68328, 68302, etc). It does not contain
a paging MMU.
config MCPU32
bool
select CPU_HAS_NO_BITFIELDS
select CPU_HAS_NO_CAS
select CPU_HAS_NO_UNALIGNED
select CPU_NO_EFFICIENT_FFS
help
The Freescale (was then Motorola) CPU32 is a CPU core that is
based on the 68020 processor. For the most part it is used in
System-On-Chip parts, and does not contain a paging MMU.
config M68020
bool "68020 support"
depends on MMU

View file

@ -203,6 +203,7 @@ config INIT_LCD
config MEMORY_RESERVE
int "Memory reservation (MiB)"
depends on (UCSIMM || UCDIMM)
default 0
help
Reserve certain memory regions on 68x328 based boards.

View file

@ -451,7 +451,7 @@ static inline unsigned long ffz(unsigned long word)
* generic functions for those.
*/
#if (defined(__mcfisaaplus__) || defined(__mcfisac__)) && \
!defined(CONFIG_M68000) && !defined(CONFIG_MCPU32)
!defined(CONFIG_M68000)
static inline unsigned long __ffs(unsigned long x)
{
__asm__ __volatile__ ("bitrev %0; ff1 %0"

View file

@ -1145,7 +1145,7 @@ asmlinkage void set_esp0(unsigned long ssp)
*/
asmlinkage void fpsp040_die(void)
{
force_sigsegv(SIGSEGV);
force_fatal_sig(SIGSEGV);
}
#ifdef CONFIG_M68KFPU_EMU

View file

@ -29,8 +29,8 @@
#define EX2(a,b) \
9: a,##b; \
.section __ex_table,"a"; \
PTR 9b,bad_stack; \
PTR 9b+4,bad_stack; \
PTR 9b,fault; \
PTR 9b+4,fault; \
.previous
.set mips1

View file

@ -240,12 +240,3 @@ SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op)
{
return -ENOSYS;
}
/*
* If we ever come here the user sp is bad. Zap the process right away.
* Due to the bad stack signaling wouldn't work.
*/
asmlinkage void bad_stack(void)
{
do_exit(SIGSEGV);
}

View file

@ -118,7 +118,7 @@ DEFINE_SPINLOCK(die_lock);
/*
* This function is protected against re-entrancy.
*/
void die(const char *str, struct pt_regs *regs, int err)
void __noreturn die(const char *str, struct pt_regs *regs, int err)
{
struct task_struct *tsk = current;
static int die_counter;

View file

@ -13,7 +13,7 @@
#include <asm/tlbflush.h>
extern void die(const char *str, struct pt_regs *regs, long err);
extern void __noreturn die(const char *str, struct pt_regs *regs, long err);
/*
* This is useful to dump out the page tables associated with
@ -299,10 +299,6 @@ no_context:
show_pte(mm, addr);
die("Oops", regs, error_code);
bust_spinlocks(0);
do_exit(SIGKILL);
return;
/*
* We ran out of memory, or some other thing happened to us that made

View file

@ -197,7 +197,7 @@ void nommu_dump_state(struct pt_regs *regs,
}
/* This is normally the 'Oops' routine */
void die(const char *str, struct pt_regs *regs, long err)
void __noreturn die(const char *str, struct pt_regs *regs, long err)
{
console_verbose();

View file

@ -32,7 +32,7 @@ unsigned long pte_errors; /* updated by do_page_fault() */
*/
volatile pgd_t *current_pgd[NR_CPUS];
extern void die(char *, struct pt_regs *, long);
extern void __noreturn die(char *, struct pt_regs *, long);
/*
* This routine handles page faults. It determines the address,
@ -248,8 +248,6 @@ no_context:
die("Oops", regs, write_acc);
do_exit(SIGKILL);
/*
* We ran out of memory, or some other thing happened to us that made
* us unable to handle the page fault gracefully.

View file

@ -1062,8 +1062,10 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
* or if another thread unmaps the region containing the context.
* We kill the task with a SIGSEGV in this situation.
*/
if (do_setcontext(new_ctx, regs, 0))
do_exit(SIGSEGV);
if (do_setcontext(new_ctx, regs, 0)) {
force_fatal_sig(SIGSEGV);
return -EFAULT;
}
set_thread_flag(TIF_RESTOREALL);
return 0;

View file

@ -703,15 +703,18 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
* We kill the task with a SIGSEGV in this situation.
*/
if (__get_user_sigset(&set, &new_ctx->uc_sigmask))
do_exit(SIGSEGV);
if (__get_user_sigset(&set, &new_ctx->uc_sigmask)) {
force_fatal_sig(SIGSEGV);
return -EFAULT;
}
set_current_blocked(&set);
if (!user_read_access_begin(new_ctx, ctx_size))
return -EFAULT;
if (__unsafe_restore_sigcontext(current, NULL, 0, &new_ctx->uc_mcontext)) {
user_read_access_end();
do_exit(SIGSEGV);
force_fatal_sig(SIGSEGV);
return -EFAULT;
}
user_read_access_end();

View file

@ -560,7 +560,7 @@ static int __kvmppc_svm_page_out(struct vm_area_struct *vma,
gpa, 0, page_shift);
if (ret == U_SUCCESS)
*mig.dst = migrate_pfn(pfn) | MIGRATE_PFN_LOCKED;
*mig.dst = migrate_pfn(pfn);
else {
unlock_page(dpage);
__free_page(dpage);
@ -774,7 +774,7 @@ static int kvmppc_svm_page_in(struct vm_area_struct *vma,
}
}
*mig.dst = migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED;
*mig.dst = migrate_pfn(page_to_pfn(dpage));
migrate_vma_pages(&mig);
out_finalize:
migrate_vma_finalize(&mig);

View file

@ -11,7 +11,7 @@
#include <linux/module.h>
#include <linux/uaccess.h>
#ifdef CONFIG_BPF_JIT
#if defined(CONFIG_BPF_JIT) && defined(CONFIG_ARCH_RV64I)
int rv_bpf_fixup_exception(const struct exception_table_entry *ex, struct pt_regs *regs);
#endif
@ -23,7 +23,7 @@ int fixup_exception(struct pt_regs *regs)
if (!fixup)
return 0;
#ifdef CONFIG_BPF_JIT
#if defined(CONFIG_BPF_JIT) && defined(CONFIG_ARCH_RV64I)
if (regs->epc >= BPF_JIT_REGION_START && regs->epc < BPF_JIT_REGION_END)
return rv_bpf_fixup_exception(fixup, regs);
#endif

View file

@ -459,6 +459,8 @@ static int emit_call(bool fixed, u64 addr, struct rv_jit_context *ctx)
#define BPF_FIXUP_OFFSET_MASK GENMASK(26, 0)
#define BPF_FIXUP_REG_MASK GENMASK(31, 27)
int rv_bpf_fixup_exception(const struct exception_table_entry *ex,
struct pt_regs *regs);
int rv_bpf_fixup_exception(const struct exception_table_entry *ex,
struct pt_regs *regs)
{

View file

@ -23,6 +23,6 @@ enum die_val {
DIE_NMI_IPI,
};
extern void die(struct pt_regs *, const char *);
extern void __noreturn die(struct pt_regs *, const char *);
#endif

View file

@ -192,7 +192,7 @@ void show_regs(struct pt_regs *regs)
static DEFINE_SPINLOCK(die_lock);
void die(struct pt_regs *regs, const char *str)
void __noreturn die(struct pt_regs *regs, const char *str)
{
static int die_counter;

View file

@ -84,7 +84,7 @@ static void default_trap_handler(struct pt_regs *regs)
{
if (user_mode(regs)) {
report_user_fault(regs, SIGSEGV, 0);
do_exit(SIGSEGV);
force_fatal_sig(SIGSEGV);
} else
die(regs, "Unknown program exception");
}

View file

@ -260,7 +260,6 @@ static noinline void do_no_context(struct pt_regs *regs)
" in virtual user address space\n");
dump_fault_info(regs);
die(regs, "Oops");
do_exit(SIGKILL);
}
static noinline void do_low_address(struct pt_regs *regs)
@ -270,7 +269,6 @@ static noinline void do_low_address(struct pt_regs *regs)
if (regs->psw.mask & PSW_MASK_PSTATE) {
/* Low-address protection hit in user mode 'cannot happen'. */
die (regs, "Low-address protection");
do_exit(SIGKILL);
}
do_no_context(regs);

View file

@ -62,18 +62,20 @@ void fpu_state_restore(struct pt_regs *regs)
}
if (!tsk_used_math(tsk)) {
local_irq_enable();
int ret;
/*
* does a slab alloc which can sleep
*/
if (init_fpu(tsk)) {
local_irq_enable();
ret = init_fpu(tsk);
local_irq_disable();
if (ret) {
/*
* ran out of memory!
*/
do_group_exit(SIGKILL);
force_sig(SIGKILL);
return;
}
local_irq_disable();
}
grab_fpu(regs);

View file

@ -20,7 +20,7 @@
static DEFINE_SPINLOCK(die_lock);
void die(const char *str, struct pt_regs *regs, long err)
void __noreturn die(const char *str, struct pt_regs *regs, long err)
{
static int die_counter;

View file

@ -238,8 +238,6 @@ no_context(struct pt_regs *regs, unsigned long error_code,
show_fault_oops(regs, address);
die("Oops", regs, error_code);
bust_spinlocks(0);
do_exit(SIGKILL);
}
static void

View file

@ -244,7 +244,7 @@ static int setup_frame(struct ksignal *ksig, struct pt_regs *regs,
get_sigframe(ksig, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size)) {
do_exit(SIGILL);
force_fatal_sig(SIGILL);
return -EINVAL;
}
@ -336,7 +336,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs,
sf = (struct rt_signal_frame __user *)
get_sigframe(ksig, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size)) {
do_exit(SIGILL);
force_fatal_sig(SIGILL);
return -EINVAL;
}

View file

@ -121,8 +121,10 @@ void try_to_clear_window_buffer(struct pt_regs *regs, int who)
if ((sp & 7) ||
copy_to_user((char __user *) sp, &tp->reg_window[window],
sizeof(struct reg_window32)))
do_exit(SIGILL);
sizeof(struct reg_window32))) {
force_fatal_sig(SIGILL);
return;
}
}
tp->w_saved = 0;
}

View file

@ -248,7 +248,6 @@ no_context:
}
unhandled_fault(address, tsk, regs);
do_exit(SIGKILL);
/*
* We ran out of memory, or some other thing happened to us that made

View file

@ -266,7 +266,7 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign
default:
printk(KERN_ERR "TSB[%s:%d]: Impossible TSB size %lu, killing process.\n",
current->comm, current->pid, tsb_bytes);
do_exit(SIGSEGV);
BUG();
}
tte |= pte_sz_bits(page_sz);

View file

@ -158,7 +158,7 @@ static void bad_segv(struct faultinfo fi, unsigned long ip)
void fatal_sigsegv(void)
{
force_sigsegv(SIGSEGV);
force_fatal_sig(SIGSEGV);
do_signal(&current->thread.regs);
/*
* This is to tell gcc that we're not returning - do_signal

View file

@ -226,7 +226,8 @@ bool emulate_vsyscall(unsigned long error_code,
if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
warn_bad_vsyscall(KERN_DEBUG, regs,
"seccomp tried to change syscall nr or ip");
do_exit(SIGSYS);
force_fatal_sig(SIGSYS);
return true;
}
regs->orig_ax = -1;
if (tmp)

View file

@ -77,9 +77,6 @@ asmlinkage noinstr void __noreturn doublefault_shim(void)
* some way to reconstruct CR3. We could make a credible guess based
* on cpu_tlbstate, but that would be racy and would not account for
* PTI.
*
* Instead, don't bother. We can return through
* rewind_stack_do_exit() instead.
*/
panic("cannot return from double fault\n");
}

View file

@ -106,10 +106,8 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
*/
local_irq_enable();
if (!vm86 || !vm86->user_vm86) {
pr_alert("no user_vm86: BAD\n");
do_exit(SIGSEGV);
}
BUG_ON(!vm86 || !vm86->user_vm86);
set_flags(regs->pt.flags, VEFLAGS, X86_EFLAGS_VIF | vm86->veflags_mask);
user = vm86->user_vm86;
@ -142,6 +140,7 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
user_access_end();
exit_vm86:
preempt_disable();
tsk->thread.sp0 = vm86->saved_sp0;
tsk->thread.sysenter_cs = __KERNEL_CS;
@ -161,7 +160,8 @@ Efault_end:
user_access_end();
Efault:
pr_alert("could not access userspace vm86 info\n");
do_exit(SIGSEGV);
force_fatal_sig(SIGSEGV);
goto exit_vm86;
}
static int do_vm86_irq_handling(int subfunction, int irqnumber);

View file

@ -527,7 +527,7 @@ void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err)
void __noreturn die(const char * str, struct pt_regs * regs, long err)
{
static int die_counter;
const char *pr = "";

View file

@ -238,7 +238,7 @@ bad_page_fault:
void
bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
{
extern void die(const char*, struct pt_regs*, long);
extern void __noreturn die(const char*, struct pt_regs*, long);
const struct exception_table_entry *entry;
/* Are we prepared to handle this kernel fault? */
@ -257,5 +257,4 @@ bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
"address %08lx\n pc = %08lx, ra = %08lx\n",
address, regs->pc, regs->areg[0]);
die("Oops", regs, sig);
do_exit(sig);
}

View file

@ -131,7 +131,7 @@ const struct attribute_group *ahci_shost_groups[] = {
};
EXPORT_SYMBOL_GPL(ahci_shost_groups);
struct attribute *ahci_sdev_attrs[] = {
static struct attribute *ahci_sdev_attrs[] = {
&dev_attr_sw_activity.attr,
&dev_attr_unload_heads.attr,
&dev_attr_ncq_prio_supported.attr,

View file

@ -2052,8 +2052,19 @@ static bool ata_identify_page_supported(struct ata_device *dev, u8 page)
struct ata_port *ap = dev->link->ap;
unsigned int err, i;
if (dev->horkage & ATA_HORKAGE_NO_ID_DEV_LOG)
return false;
if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE)) {
ata_dev_warn(dev, "ATA Identify Device Log not supported\n");
/*
* IDENTIFY DEVICE data log is defined as mandatory starting
* with ACS-3 (ATA version 10). Warn about the missing log
* for drives which implement this ATA level or above.
*/
if (ata_id_major_version(dev->id) >= 10)
ata_dev_warn(dev,
"ATA Identify Device Log not supported\n");
dev->horkage |= ATA_HORKAGE_NO_ID_DEV_LOG;
return false;
}

View file

@ -93,6 +93,12 @@ static const unsigned long ata_eh_identify_timeouts[] = {
ULONG_MAX,
};
static const unsigned long ata_eh_revalidate_timeouts[] = {
15000, /* Some drives are slow to read log pages when waking-up */
15000, /* combined time till here is enough even for media access */
ULONG_MAX,
};
static const unsigned long ata_eh_flush_timeouts[] = {
15000, /* be generous with flush */
15000, /* ditto */
@ -129,6 +135,8 @@ static const struct ata_eh_cmd_timeout_ent
ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
{ .commands = CMDS(ATA_CMD_ID_ATA, ATA_CMD_ID_ATAPI),
.timeouts = ata_eh_identify_timeouts, },
{ .commands = CMDS(ATA_CMD_READ_LOG_EXT, ATA_CMD_READ_LOG_DMA_EXT),
.timeouts = ata_eh_revalidate_timeouts, },
{ .commands = CMDS(ATA_CMD_READ_NATIVE_MAX, ATA_CMD_READ_NATIVE_MAX_EXT),
.timeouts = ata_eh_other_timeouts, },
{ .commands = CMDS(ATA_CMD_SET_MAX, ATA_CMD_SET_MAX_EXT),

View file

@ -469,10 +469,8 @@ static int ahci_highbank_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "no irq\n");
if (irq < 0)
return irq;
}
if (!irq)
return -EINVAL;

View file

@ -520,7 +520,7 @@ static int svc_normal_to_secure_thread(void *data)
* physical address of memory block reserved by secure monitor software at
* secure world.
*
* svc_normal_to_secure_shm_thread() calls do_exit() directly since it is a
* svc_normal_to_secure_shm_thread() terminates directly since it is a
* standlone thread for which no one will call kthread_stop() or return when
* 'kthread_should_stop()' is true.
*/
@ -544,7 +544,7 @@ static int svc_normal_to_secure_shm_thread(void *data)
}
complete(&sh_mem->sync_complete);
do_exit(0);
return 0;
}
/**

View file

@ -317,7 +317,6 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]);
svm_migrate_get_vram_page(prange, migrate->dst[i]);
migrate->dst[i] = migrate_pfn(migrate->dst[i]);
migrate->dst[i] |= MIGRATE_PFN_LOCKED;
src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE,
DMA_TO_DEVICE);
r = dma_mapping_error(dev, src[i]);
@ -610,7 +609,6 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
dst[i] >> PAGE_SHIFT, page_to_pfn(dpage));
migrate->dst[i] = migrate_pfn(page_to_pfn(dpage));
migrate->dst[i] |= MIGRATE_PFN_LOCKED;
j++;
}

View file

@ -166,7 +166,7 @@ static vm_fault_t nouveau_dmem_fault_copy_one(struct nouveau_drm *drm,
goto error_dma_unmap;
mutex_unlock(&svmm->mutex);
args->dst[0] = migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED;
args->dst[0] = migrate_pfn(page_to_pfn(dpage));
return 0;
error_dma_unmap:
@ -602,7 +602,7 @@ static unsigned long nouveau_dmem_migrate_copy_one(struct nouveau_drm *drm,
((paddr >> PAGE_SHIFT) << NVIF_VMM_PFNMAP_V0_ADDR_SHIFT);
if (src & MIGRATE_PFN_WRITE)
*pfn |= NVIF_VMM_PFNMAP_V0_W;
return migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED;
return migrate_pfn(page_to_pfn(dpage));
out_dma_unmap:
dma_unmap_page(dev, *dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL);

View file

@ -19,6 +19,7 @@
#include <linux/input.h>
#include <linux/gameport.h>
#include <linux/jiffies.h>
#include <linux/seq_buf.h>
#include <linux/timex.h>
#include <linux/timekeeping.h>
@ -338,23 +339,24 @@ static void analog_calibrate_timer(struct analog_port *port)
static void analog_name(struct analog *analog)
{
snprintf(analog->name, sizeof(analog->name), "Analog %d-axis %d-button",
struct seq_buf s;
seq_buf_init(&s, analog->name, sizeof(analog->name));
seq_buf_printf(&s, "Analog %d-axis %d-button",
hweight8(analog->mask & ANALOG_AXES_STD),
hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
if (analog->mask & ANALOG_HATS_ALL)
snprintf(analog->name, sizeof(analog->name), "%s %d-hat",
analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
seq_buf_printf(&s, " %d-hat",
hweight16(analog->mask & ANALOG_HATS_ALL));
if (analog->mask & ANALOG_HAT_FCS)
strlcat(analog->name, " FCS", sizeof(analog->name));
seq_buf_printf(&s, " FCS");
if (analog->mask & ANALOG_ANY_CHF)
strlcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF",
sizeof(analog->name));
seq_buf_printf(&s, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
strlcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick",
sizeof(analog->name));
seq_buf_printf(&s, (analog->mask & ANALOG_GAMEPAD) ? " gamepad" : " joystick");
}
/*

View file

@ -92,7 +92,7 @@ static int iforce_usb_get_id(struct iforce *iforce, u8 id,
id,
USB_TYPE_VENDOR | USB_DIR_IN |
USB_RECIP_INTERFACE,
0, 0, buf, IFORCE_MAX_LENGTH, HZ);
0, 0, buf, IFORCE_MAX_LENGTH, 1000);
if (status < 0) {
dev_err(&iforce_usb->intf->dev,
"usb_submit_urb failed: %d\n", status);

View file

@ -83,7 +83,7 @@ static const struct tmdc_model {
const signed char *axes;
const short *buttons;
} tmdc_models[] = {
{ 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
{ 1, "ThrustMaster Millennium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
{ 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
{ 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
{ 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },

View file

@ -788,4 +788,14 @@ config KEYBOARD_MTK_PMIC
To compile this driver as a module, choose M here: the
module will be called pmic-keys.
config KEYBOARD_CYPRESS_SF
tristate "Cypress StreetFighter touchkey support"
depends on I2C
help
Say Y here if you want to enable support for Cypress StreetFighter
touchkeys.
To compile this driver as a module, choose M here: the
module will be called cypress-sf.
endif

View file

@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o
obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_CYPRESS_SF) += cypress-sf.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_DLINK_DIR685) += dlink-dir685-touchkeys.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o

View file

@ -91,18 +91,21 @@ struct cap11xx_hw_model {
u8 product_id;
unsigned int num_channels;
unsigned int num_leds;
bool no_gain;
};
enum {
CAP1106,
CAP1126,
CAP1188,
CAP1206,
};
static const struct cap11xx_hw_model cap11xx_devices[] = {
[CAP1106] = { .product_id = 0x55, .num_channels = 6, .num_leds = 0 },
[CAP1126] = { .product_id = 0x53, .num_channels = 6, .num_leds = 2 },
[CAP1188] = { .product_id = 0x50, .num_channels = 8, .num_leds = 8 },
[CAP1106] = { .product_id = 0x55, .num_channels = 6, .num_leds = 0, .no_gain = false },
[CAP1126] = { .product_id = 0x53, .num_channels = 6, .num_leds = 2, .no_gain = false },
[CAP1188] = { .product_id = 0x50, .num_channels = 8, .num_leds = 8, .no_gain = false },
[CAP1206] = { .product_id = 0x67, .num_channels = 6, .num_leds = 0, .no_gain = true },
};
static const struct reg_default cap11xx_reg_defaults[] = {
@ -378,17 +381,24 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
node = dev->of_node;
if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) {
if (is_power_of_2(gain32) && gain32 <= 8)
if (cap->no_gain)
dev_warn(dev,
"This version doesn't support sensor gain\n");
else if (is_power_of_2(gain32) && gain32 <= 8)
gain = ilog2(gain32);
else
dev_err(dev, "Invalid sensor-gain value %d\n", gain32);
}
if (of_property_read_bool(node, "microchip,irq-active-high")) {
error = regmap_update_bits(priv->regmap, CAP11XX_REG_CONFIG2,
CAP11XX_REG_CONFIG2_ALT_POL, 0);
if (error)
return error;
if (id->driver_data != CAP1206) {
if (of_property_read_bool(node, "microchip,irq-active-high")) {
error = regmap_update_bits(priv->regmap,
CAP11XX_REG_CONFIG2,
CAP11XX_REG_CONFIG2_ALT_POL,
0);
if (error)
return error;
}
}
/* Provide some useful defaults */
@ -398,11 +408,14 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
of_property_read_u32_array(node, "linux,keycodes",
priv->keycodes, cap->num_channels);
error = regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL,
CAP11XX_REG_MAIN_CONTROL_GAIN_MASK,
gain << CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT);
if (error)
return error;
if (!cap->no_gain) {
error = regmap_update_bits(priv->regmap,
CAP11XX_REG_MAIN_CONTROL,
CAP11XX_REG_MAIN_CONTROL_GAIN_MASK,
gain << CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT);
if (error)
return error;
}
/* Disable autorepeat. The Linux input system has its own handling. */
error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
@ -470,6 +483,7 @@ static const struct of_device_id cap11xx_dt_ids[] = {
{ .compatible = "microchip,cap1106", },
{ .compatible = "microchip,cap1126", },
{ .compatible = "microchip,cap1188", },
{ .compatible = "microchip,cap1206", },
{}
};
MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
@ -478,6 +492,7 @@ static const struct i2c_device_id cap11xx_i2c_ids[] = {
{ "cap1106", CAP1106 },
{ "cap1126", CAP1126 },
{ "cap1188", CAP1188 },
{ "cap1206", CAP1206 },
{}
};
MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids);

View file

@ -0,0 +1,224 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Cypress StreetFighter Touchkey Driver
*
* Copyright (c) 2021 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#define CYPRESS_SF_DEV_NAME "cypress-sf"
#define CYPRESS_SF_REG_BUTTON_STATUS 0x4a
struct cypress_sf_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct regulator_bulk_data regulators[2];
u32 *keycodes;
unsigned long keystates;
int num_keys;
};
static irqreturn_t cypress_sf_irq_handler(int irq, void *devid)
{
struct cypress_sf_data *touchkey = devid;
unsigned long keystates, changed;
bool new_state;
int val, key;
val = i2c_smbus_read_byte_data(touchkey->client,
CYPRESS_SF_REG_BUTTON_STATUS);
if (val < 0) {
dev_err(&touchkey->client->dev,
"Failed to read button status: %d", val);
return IRQ_NONE;
}
keystates = val;
bitmap_xor(&changed, &keystates, &touchkey->keystates,
touchkey->num_keys);
for_each_set_bit(key, &changed, touchkey->num_keys) {
new_state = keystates & BIT(key);
dev_dbg(&touchkey->client->dev,
"Key %d changed to %d", key, new_state);
input_report_key(touchkey->input_dev,
touchkey->keycodes[key], new_state);
}
input_sync(touchkey->input_dev);
touchkey->keystates = keystates;
return IRQ_HANDLED;
}
static int cypress_sf_probe(struct i2c_client *client)
{
struct cypress_sf_data *touchkey;
int key, error;
touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL);
if (!touchkey)
return -ENOMEM;
touchkey->client = client;
i2c_set_clientdata(client, touchkey);
touchkey->regulators[0].supply = "vdd";
touchkey->regulators[1].supply = "avdd";
error = devm_regulator_bulk_get(&client->dev,
ARRAY_SIZE(touchkey->regulators),
touchkey->regulators);
if (error) {
dev_err(&client->dev, "Failed to get regulators: %d\n", error);
return error;
}
touchkey->num_keys = device_property_read_u32_array(&client->dev,
"linux,keycodes",
NULL, 0);
if (touchkey->num_keys < 0) {
/* Default key count */
touchkey->num_keys = 2;
}
touchkey->keycodes = devm_kcalloc(&client->dev,
touchkey->num_keys,
sizeof(*touchkey->keycodes),
GFP_KERNEL);
if (!touchkey->keycodes)
return -ENOMEM;
error = device_property_read_u32_array(&client->dev, "linux,keycodes",
touchkey->keycodes,
touchkey->num_keys);
if (error) {
dev_warn(&client->dev,
"Failed to read keycodes: %d, using defaults\n",
error);
/* Default keycodes */
touchkey->keycodes[0] = KEY_BACK;
touchkey->keycodes[1] = KEY_MENU;
}
error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
touchkey->regulators);
if (error) {
dev_err(&client->dev,
"Failed to enable regulators: %d\n", error);
return error;
}
touchkey->input_dev = devm_input_allocate_device(&client->dev);
if (!touchkey->input_dev) {
dev_err(&client->dev, "Failed to allocate input device\n");
return -ENOMEM;
}
touchkey->input_dev->name = CYPRESS_SF_DEV_NAME;
touchkey->input_dev->id.bustype = BUS_I2C;
for (key = 0; key < touchkey->num_keys; ++key)
input_set_capability(touchkey->input_dev,
EV_KEY, touchkey->keycodes[key]);
error = input_register_device(touchkey->input_dev);
if (error) {
dev_err(&client->dev,
"Failed to register input device: %d\n", error);
return error;
}
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, cypress_sf_irq_handler,
IRQF_ONESHOT,
CYPRESS_SF_DEV_NAME, touchkey);
if (error) {
dev_err(&client->dev,
"Failed to register threaded irq: %d", error);
return error;
}
return 0;
};
static int __maybe_unused cypress_sf_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cypress_sf_data *touchkey = i2c_get_clientdata(client);
int error;
disable_irq(client->irq);
error = regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
touchkey->regulators);
if (error) {
dev_err(dev, "Failed to disable regulators: %d", error);
enable_irq(client->irq);
return error;
}
return 0;
}
static int __maybe_unused cypress_sf_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cypress_sf_data *touchkey = i2c_get_clientdata(client);
int error;
error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
touchkey->regulators);
if (error) {
dev_err(dev, "Failed to enable regulators: %d", error);
return error;
}
enable_irq(client->irq);
return 0;
}
static SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops,
cypress_sf_suspend, cypress_sf_resume);
static struct i2c_device_id cypress_sf_id_table[] = {
{ CYPRESS_SF_DEV_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table);
#ifdef CONFIG_OF
static const struct of_device_id cypress_sf_of_match[] = {
{ .compatible = "cypress,sf3155", },
{ },
};
MODULE_DEVICE_TABLE(of, cypress_sf_of_match);
#endif
static struct i2c_driver cypress_sf_driver = {
.driver = {
.name = CYPRESS_SF_DEV_NAME,
.pm = &cypress_sf_pm_ops,
.of_match_table = of_match_ptr(cypress_sf_of_match),
},
.id_table = cypress_sf_id_table,
.probe_new = cypress_sf_probe,
};
module_i2c_driver(cypress_sf_driver);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("Cypress StreetFighter Touchkey Driver");
MODULE_LICENSE("GPL v2");

View file

@ -17,6 +17,7 @@
* flag.
*/
#include <linux/bits.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
@ -26,6 +27,7 @@
#include <linux/slab.h>
#include <linux/soc/cirrus/ep93xx.h>
#include <linux/platform_data/keypad-ep93xx.h>
#include <linux/pm_wakeirq.h>
/*
* Keypad Interface Register offsets
@ -35,28 +37,28 @@
#define KEY_REG 0x08 /* Key Value Capture register */
/* Key Scan Initialization Register bit defines */
#define KEY_INIT_DBNC_MASK (0x00ff0000)
#define KEY_INIT_DBNC_SHIFT (16)
#define KEY_INIT_DIS3KY (1<<15)
#define KEY_INIT_DIAG (1<<14)
#define KEY_INIT_BACK (1<<13)
#define KEY_INIT_T2 (1<<12)
#define KEY_INIT_PRSCL_MASK (0x000003ff)
#define KEY_INIT_PRSCL_SHIFT (0)
#define KEY_INIT_DBNC_MASK GENMASK(23, 16)
#define KEY_INIT_DBNC_SHIFT 16
#define KEY_INIT_DIS3KY BIT(15)
#define KEY_INIT_DIAG BIT(14)
#define KEY_INIT_BACK BIT(13)
#define KEY_INIT_T2 BIT(12)
#define KEY_INIT_PRSCL_MASK GENMASK(9, 0)
#define KEY_INIT_PRSCL_SHIFT 0
/* Key Scan Diagnostic Register bit defines */
#define KEY_DIAG_MASK (0x0000003f)
#define KEY_DIAG_SHIFT (0)
#define KEY_DIAG_MASK GENMASK(5, 0)
#define KEY_DIAG_SHIFT 0
/* Key Value Capture Register bit defines */
#define KEY_REG_K (1<<15)
#define KEY_REG_INT (1<<14)
#define KEY_REG_2KEYS (1<<13)
#define KEY_REG_1KEY (1<<12)
#define KEY_REG_KEY2_MASK (0x00000fc0)
#define KEY_REG_KEY2_SHIFT (6)
#define KEY_REG_KEY1_MASK (0x0000003f)
#define KEY_REG_KEY1_SHIFT (0)
#define KEY_REG_K BIT(15)
#define KEY_REG_INT BIT(14)
#define KEY_REG_2KEYS BIT(13)
#define KEY_REG_1KEY BIT(12)
#define KEY_REG_KEY2_MASK GENMASK(11, 6)
#define KEY_REG_KEY2_SHIFT 6
#define KEY_REG_KEY1_MASK GENMASK(5, 0)
#define KEY_REG_KEY1_SHIFT 0
#define EP93XX_MATRIX_SIZE (EP93XX_MATRIX_ROWS * EP93XX_MATRIX_COLS)
@ -175,8 +177,7 @@ static void ep93xx_keypad_close(struct input_dev *pdev)
}
#ifdef CONFIG_PM_SLEEP
static int ep93xx_keypad_suspend(struct device *dev)
static int __maybe_unused ep93xx_keypad_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
@ -191,21 +192,15 @@ static int ep93xx_keypad_suspend(struct device *dev)
mutex_unlock(&input_dev->mutex);
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(keypad->irq);
return 0;
}
static int ep93xx_keypad_resume(struct device *dev)
static int __maybe_unused ep93xx_keypad_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(keypad->irq);
mutex_lock(&input_dev->mutex);
if (input_device_enabled(input_dev)) {
@ -220,11 +215,17 @@ static int ep93xx_keypad_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops,
ep93xx_keypad_suspend, ep93xx_keypad_resume);
static void ep93xx_keypad_release_gpio_action(void *_pdev)
{
struct platform_device *pdev = _pdev;
ep93xx_keypad_release_gpio(pdev);
}
static int ep93xx_keypad_probe(struct platform_device *pdev)
{
struct ep93xx_keypad *keypad;
@ -233,61 +234,46 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
struct resource *res;
int err;
keypad = kzalloc(sizeof(struct ep93xx_keypad), GFP_KERNEL);
keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
if (!keypad)
return -ENOMEM;
keypad->pdata = dev_get_platdata(&pdev->dev);
if (!keypad->pdata) {
err = -EINVAL;
goto failed_free;
}
if (!keypad->pdata)
return -EINVAL;
keymap_data = keypad->pdata->keymap_data;
if (!keymap_data) {
err = -EINVAL;
goto failed_free;
}
if (!keymap_data)
return -EINVAL;
keypad->irq = platform_get_irq(pdev, 0);
if (keypad->irq < 0) {
err = keypad->irq;
goto failed_free;
}
if (keypad->irq < 0)
return keypad->irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
err = -ENXIO;
goto failed_free;
}
if (!res)
return -ENXIO;
res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) {
err = -EBUSY;
goto failed_free;
}
keypad->mmio_base = ioremap(res->start, resource_size(res));
if (keypad->mmio_base == NULL) {
err = -ENXIO;
goto failed_free_mem;
}
keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(keypad->mmio_base))
return PTR_ERR(keypad->mmio_base);
err = ep93xx_keypad_acquire_gpio(pdev);
if (err)
goto failed_free_io;
return err;
keypad->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(keypad->clk)) {
err = PTR_ERR(keypad->clk);
goto failed_free_gpio;
}
err = devm_add_action_or_reset(&pdev->dev,
ep93xx_keypad_release_gpio_action, pdev);
if (err)
return err;
input_dev = input_allocate_device();
if (!input_dev) {
err = -ENOMEM;
goto failed_put_clk;
}
keypad->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(keypad->clk))
return PTR_ERR(keypad->clk);
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev)
return -ENOMEM;
keypad->input_dev = input_dev;
@ -295,70 +281,40 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
input_dev->id.bustype = BUS_HOST;
input_dev->open = ep93xx_keypad_open;
input_dev->close = ep93xx_keypad_close;
input_dev->dev.parent = &pdev->dev;
err = matrix_keypad_build_keymap(keymap_data, NULL,
EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS,
keypad->keycodes, input_dev);
if (err)
goto failed_free_dev;
return err;
if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
__set_bit(EV_REP, input_dev->evbit);
input_set_drvdata(input_dev, keypad);
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
0, pdev->name, keypad);
err = devm_request_irq(&pdev->dev, keypad->irq,
ep93xx_keypad_irq_handler,
0, pdev->name, keypad);
if (err)
goto failed_free_dev;
return err;
err = input_register_device(input_dev);
if (err)
goto failed_free_irq;
return err;
platform_set_drvdata(pdev, keypad);
device_init_wakeup(&pdev->dev, 1);
err = dev_pm_set_wake_irq(&pdev->dev, keypad->irq);
if (err)
dev_warn(&pdev->dev, "failed to set up wakeup irq: %d\n", err);
return 0;
failed_free_irq:
free_irq(keypad->irq, keypad);
failed_free_dev:
input_free_device(input_dev);
failed_put_clk:
clk_put(keypad->clk);
failed_free_gpio:
ep93xx_keypad_release_gpio(pdev);
failed_free_io:
iounmap(keypad->mmio_base);
failed_free_mem:
release_mem_region(res->start, resource_size(res));
failed_free:
kfree(keypad);
return err;
}
static int ep93xx_keypad_remove(struct platform_device *pdev)
{
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
free_irq(keypad->irq, keypad);
if (keypad->enabled)
clk_disable(keypad->clk);
clk_put(keypad->clk);
input_unregister_device(keypad->input_dev);
ep93xx_keypad_release_gpio(pdev);
iounmap(keypad->mmio_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
kfree(keypad);
dev_pm_clear_wake_irq(&pdev->dev);
return 0;
}

View file

@ -107,9 +107,9 @@ static struct regulator *mpr121_vdd_supply_init(struct device *dev)
return ERR_PTR(err);
}
err = devm_add_action(dev, mpr121_vdd_supply_disable, vdd_supply);
err = devm_add_action_or_reset(dev, mpr121_vdd_supply_disable,
vdd_supply);
if (err) {
regulator_disable(vdd_supply);
dev_err(dev, "failed to add disable regulator action: %d\n",
err);
return ERR_PTR(err);

View file

@ -190,8 +190,7 @@ static int omap_kp_probe(struct platform_device *pdev)
row_shift = get_count_order(pdata->cols);
keycodemax = pdata->rows << row_shift;
omap_kp = kzalloc(sizeof(struct omap_kp) +
keycodemax * sizeof(unsigned short), GFP_KERNEL);
omap_kp = kzalloc(struct_size(omap_kp, keymap, keycodemax), GFP_KERNEL);
input_dev = input_allocate_device();
if (!omap_kp || !input_dev) {
kfree(omap_kp);

View file

@ -156,6 +156,8 @@ static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid)
goto out;
}
input_event(touchkey->input_dev, EV_MSC, MSC_SCAN, index);
if (data & TM2_TOUCHKEY_BIT_PRESS_EV) {
for (i = 0; i < touchkey->num_keycodes; i++)
input_report_key(touchkey->input_dev,
@ -250,6 +252,11 @@ static int tm2_touchkey_probe(struct i2c_client *client,
touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME;
touchkey->input_dev->id.bustype = BUS_I2C;
touchkey->input_dev->keycode = touchkey->keycodes;
touchkey->input_dev->keycodemax = touchkey->num_keycodes;
touchkey->input_dev->keycodesize = sizeof(touchkey->keycodes[0]);
input_set_capability(touchkey->input_dev, EV_MSC, MSC_SCAN);
for (i = 0; i < touchkey->num_keycodes; i++)
input_set_capability(touchkey->input_dev, EV_KEY,
touchkey->keycodes[i]);

View file

@ -103,7 +103,9 @@ static int adxl34x_i2c_remove(struct i2c_client *client)
{
struct adxl34x *ac = i2c_get_clientdata(client);
return adxl34x_remove(ac);
adxl34x_remove(ac);
return 0;
}
static int __maybe_unused adxl34x_i2c_suspend(struct device *dev)

View file

@ -91,7 +91,9 @@ static int adxl34x_spi_remove(struct spi_device *spi)
{
struct adxl34x *ac = spi_get_drvdata(spi);
return adxl34x_remove(ac);
adxl34x_remove(ac);
return 0;
}
static int __maybe_unused adxl34x_spi_suspend(struct device *dev)

View file

@ -237,7 +237,7 @@ static const struct adxl34x_platform_data adxl34x_default_init = {
static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
{
short buf[3];
__le16 buf[3];
ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf);
@ -896,15 +896,13 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
}
EXPORT_SYMBOL_GPL(adxl34x_probe);
int adxl34x_remove(struct adxl34x *ac)
void adxl34x_remove(struct adxl34x *ac)
{
sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group);
free_irq(ac->irq, ac);
input_unregister_device(ac->input);
dev_dbg(ac->dev, "unregistered accelerometer\n");
kfree(ac);
return 0;
}
EXPORT_SYMBOL_GPL(adxl34x_remove);

View file

@ -25,6 +25,6 @@ void adxl34x_resume(struct adxl34x *ac);
struct adxl34x *adxl34x_probe(struct device *dev, int irq,
bool fifo_delay_default,
const struct adxl34x_bus_ops *bops);
int adxl34x_remove(struct adxl34x *ac);
void adxl34x_remove(struct adxl34x *ac);
#endif

View file

@ -149,12 +149,19 @@ static const struct of_device_id ariel_pwrbutton_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ariel_pwrbutton_of_match);
static const struct spi_device_id ariel_pwrbutton_spi_ids[] = {
{ .name = "wyse-ariel-ec-input" },
{ }
};
MODULE_DEVICE_TABLE(spi, ariel_pwrbutton_spi_ids);
static struct spi_driver ariel_pwrbutton_driver = {
.driver = {
.name = "dell-wyse-ariel-ec-input",
.of_match_table = ariel_pwrbutton_of_match,
},
.probe = ariel_pwrbutton_probe,
.id_table = ariel_pwrbutton_spi_ids,
};
module_spi_driver(ariel_pwrbutton_driver);

View file

@ -54,9 +54,13 @@ static irqreturn_t powerbutton_irq(int irq, void *_button)
static int cpcap_power_button_probe(struct platform_device *pdev)
{
struct cpcap_power_button *button;
int irq = platform_get_irq(pdev, 0);
int irq;
int err;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
button = devm_kmalloc(&pdev->dev, sizeof(*button), GFP_KERNEL);
if (!button)
return -ENOMEM;
@ -73,7 +77,6 @@ static int cpcap_power_button_probe(struct platform_device *pdev)
button->idev->name = "cpcap-pwrbutton";
button->idev->phys = "cpcap-pwrbutton/input0";
button->idev->dev.parent = button->dev;
input_set_capability(button->idev, EV_KEY, KEY_POWER);
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,

View file

@ -424,5 +424,4 @@ module_platform_driver(max77693_haptic_driver);
MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver");
MODULE_ALIAS("platform:max77693-haptic");
MODULE_LICENSE("GPL");

View file

@ -1,4 +1,4 @@
/**
/*
* MAX8925 ONKEY driver
*
* Copyright (C) 2009 Marvell International Ltd.

View file

@ -210,6 +210,11 @@ static int palmas_pwron_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work);
pwron->irq = platform_get_irq(pdev, 0);
if (pwron->irq < 0) {
error = pwron->irq;
goto err_free_input;
}
error = request_threaded_irq(pwron->irq, NULL, pwron_irq,
IRQF_TRIGGER_HIGH |
IRQF_TRIGGER_LOW |

View file

@ -29,6 +29,7 @@
#define PON_PS_HOLD_RST_CTL2 0x5b
#define PON_PS_HOLD_ENABLE BIT(7)
#define PON_PS_HOLD_TYPE_MASK 0x0f
#define PON_PS_HOLD_TYPE_WARM_RESET 1
#define PON_PS_HOLD_TYPE_SHUTDOWN 4
#define PON_PS_HOLD_TYPE_HARD_RESET 7
@ -99,7 +100,10 @@ static int pm8941_reboot_notify(struct notifier_block *nb,
break;
case SYS_RESTART:
default:
reset_type = PON_PS_HOLD_TYPE_HARD_RESET;
if (reboot_mode == REBOOT_WARM)
reset_type = PON_PS_HOLD_TYPE_WARM_RESET;
else
reset_type = PON_PS_HOLD_TYPE_HARD_RESET;
break;
}

View file

@ -517,6 +517,19 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
case 0x16008020U:
case 0x26800010U:
case 0x36808000U:
/*
* This firmware misreport coordinates for trackpoint
* occasionally. Discard packets outside of [-127, 127] range
* to prevent cursor jumps.
*/
if (packet[4] == 0x80 || packet[5] == 0x80 ||
packet[1] >> 7 == packet[4] >> 7 ||
packet[2] >> 7 == packet[5] >> 7) {
elantech_debug("discarding packet [%6ph]\n", packet);
break;
}
x = packet[4] - (int)((packet[1]^0x80) << 1);
y = (int)((packet[2]^0x80) << 1) - packet[5];

View file

@ -90,6 +90,7 @@ int rmi_register_transport_device(struct rmi_transport_dev *xport)
rmi_dev->dev.bus = &rmi_bus_type;
rmi_dev->dev.type = &rmi_device_type;
rmi_dev->dev.parent = xport->dev;
xport->rmi_dev = rmi_dev;

View file

@ -272,6 +272,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
},
},
{
/* Fujitsu Lifebook T725 laptop */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"),
},
},
{
/* Fujitsu Lifebook U745 */
.matches = {
@ -840,6 +847,13 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"),
},
},
{
/* Fujitsu Lifebook T725 laptop */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"),
},
},
{
/* Fujitsu U574 laptop */
/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */

View file

@ -425,6 +425,7 @@ config TOUCHSCREEN_HYCON_HY46XX
config TOUCHSCREEN_ILI210X
tristate "Ilitek ILI210X based touchscreen"
depends on I2C
select CRC_CCITT
help
Say Y here if you have a ILI210X based touchscreen
controller. This driver supports models ILI2102,

View file

@ -6,6 +6,7 @@
# Each configuration option enables a list of files.
wm97xx-ts-y := wm97xx-core.o
goodix_ts-y := goodix.o goodix_fwupload.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
@ -44,7 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o

View file

@ -101,10 +101,6 @@ struct ads7846 {
struct spi_device *spi;
struct regulator *reg;
#if IS_ENABLED(CONFIG_HWMON)
struct device *hwmon;
#endif
u16 model;
u16 vref_mv;
u16 vref_delay_usecs;
@ -142,13 +138,18 @@ struct ads7846 {
int (*filter)(void *data, int data_idx, int *val);
void *filter_data;
void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void);
int gpio_pendown;
void (*wait_for_sync)(void);
};
enum ads7846_filter {
ADS7846_FILTER_OK,
ADS7846_FILTER_REPEAT,
ADS7846_FILTER_IGNORE,
};
/* leave chip selected when we're done, for quicker re-select? */
#if 0
#define CS_CHANGE(xfer) ((xfer).cs_change = 1)
@ -549,6 +550,8 @@ __ATTRIBUTE_GROUPS(ads7846_attr);
static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
{
struct device *hwmon;
/* hwmon sensors need a reference voltage */
switch (ts->model) {
case 7846:
@ -569,17 +572,11 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
break;
}
ts->hwmon = hwmon_device_register_with_groups(&spi->dev, spi->modalias,
ts, ads7846_attr_groups);
hwmon = devm_hwmon_device_register_with_groups(&spi->dev,
spi->modalias, ts,
ads7846_attr_groups);
return PTR_ERR_OR_ZERO(ts->hwmon);
}
static void ads784x_hwmon_unregister(struct spi_device *spi,
struct ads7846 *ts)
{
if (ts->hwmon)
hwmon_device_unregister(ts->hwmon);
return PTR_ERR_OR_ZERO(hwmon);
}
#else
@ -588,11 +585,6 @@ static inline int ads784x_hwmon_register(struct spi_device *spi,
{
return 0;
}
static inline void ads784x_hwmon_unregister(struct spi_device *spi,
struct ads7846 *ts)
{
}
#endif
static ssize_t ads7846_pen_down_show(struct device *dev,
@ -1014,8 +1006,8 @@ static int ads7846_setup_pendown(struct spi_device *spi,
ts->get_pendown_state = pdata->get_pendown_state;
} else if (gpio_is_valid(pdata->gpio_pendown)) {
err = gpio_request_one(pdata->gpio_pendown, GPIOF_IN,
"ads7846_pendown");
err = devm_gpio_request_one(&spi->dev, pdata->gpio_pendown,
GPIOF_IN, "ads7846_pendown");
if (err) {
dev_err(&spi->dev,
"failed to request/setup pendown GPIO%d: %d\n",
@ -1212,24 +1204,30 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
}
#endif
static void ads7846_regulator_disable(void *regulator)
{
regulator_disable(regulator);
}
static int ads7846_probe(struct spi_device *spi)
{
const struct ads7846_platform_data *pdata;
struct ads7846 *ts;
struct device *dev = &spi->dev;
struct ads7846_packet *packet;
struct input_dev *input_dev;
unsigned long irq_flags;
int err;
if (!spi->irq) {
dev_dbg(&spi->dev, "no IRQ?\n");
dev_dbg(dev, "no IRQ?\n");
return -EINVAL;
}
/* don't exceed max specified sample rate */
if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
dev_err(&spi->dev, "f(sample) %d KHz?\n",
(spi->max_speed_hz/SAMPLE_BITS)/1000);
dev_err(dev, "f(sample) %d KHz?\n",
(spi->max_speed_hz/SAMPLE_BITS)/1000);
return -EINVAL;
}
@ -1245,13 +1243,17 @@ static int ads7846_probe(struct spi_device *spi)
if (err < 0)
return err;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !packet || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
ts = devm_kzalloc(dev, sizeof(struct ads7846), GFP_KERNEL);
if (!ts)
return -ENOMEM;
packet = devm_kzalloc(dev, sizeof(struct ads7846_packet), GFP_KERNEL);
if (!packet)
return -ENOMEM;
input_dev = devm_input_allocate_device(dev);
if (!input_dev)
return -ENOMEM;
spi_set_drvdata(spi, ts);
@ -1262,13 +1264,11 @@ static int ads7846_probe(struct spi_device *spi)
mutex_init(&ts->lock);
init_waitqueue_head(&ts->wait);
pdata = dev_get_platdata(&spi->dev);
pdata = dev_get_platdata(dev);
if (!pdata) {
pdata = ads7846_probe_dt(&spi->dev);
if (IS_ERR(pdata)) {
err = PTR_ERR(pdata);
goto err_free_mem;
}
pdata = ads7846_probe_dt(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
ts->model = pdata->model ? : 7846;
@ -1276,15 +1276,7 @@ static int ads7846_probe(struct spi_device *spi)
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->vref_mv = pdata->vref_mv;
if (pdata->filter != NULL) {
if (pdata->filter_init != NULL) {
err = pdata->filter_init(pdata, &ts->filter_data);
if (err < 0)
goto err_free_mem;
}
ts->filter = pdata->filter;
ts->filter_cleanup = pdata->filter_cleanup;
} else if (pdata->debounce_max) {
if (pdata->debounce_max) {
ts->debounce_max = pdata->debounce_max;
if (ts->debounce_max < 2)
ts->debounce_max = 2;
@ -1298,7 +1290,7 @@ static int ads7846_probe(struct spi_device *spi)
err = ads7846_setup_pendown(spi, ts, pdata);
if (err)
goto err_cleanup_filter;
return err;
if (pdata->penirq_recheck_delay_usecs)
ts->penirq_recheck_delay_usecs =
@ -1306,15 +1298,16 @@ static int ads7846_probe(struct spi_device *spi)
ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
input_dev->name = ts->name;
input_dev->phys = ts->phys;
input_dev->dev.parent = &spi->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_dev->id.bustype = BUS_SPI;
input_dev->id.product = pdata->model;
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
pdata->x_min ? : 0,
pdata->x_max ? : MAX_12BIT,
@ -1345,125 +1338,84 @@ static int ads7846_probe(struct spi_device *spi)
ads7846_setup_spi_msg(ts, pdata);
ts->reg = regulator_get(&spi->dev, "vcc");
ts->reg = devm_regulator_get(dev, "vcc");
if (IS_ERR(ts->reg)) {
err = PTR_ERR(ts->reg);
dev_err(&spi->dev, "unable to get regulator: %d\n", err);
goto err_free_gpio;
dev_err(dev, "unable to get regulator: %d\n", err);
return err;
}
err = regulator_enable(ts->reg);
if (err) {
dev_err(&spi->dev, "unable to enable regulator: %d\n", err);
goto err_put_regulator;
dev_err(dev, "unable to enable regulator: %d\n", err);
return err;
}
err = devm_add_action_or_reset(dev, ads7846_regulator_disable, ts->reg);
if (err)
return err;
irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
irq_flags |= IRQF_ONESHOT;
err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq,
irq_flags, spi->dev.driver->name, ts);
if (err && !pdata->irq_flags) {
dev_info(&spi->dev,
err = devm_request_threaded_irq(dev, spi->irq,
ads7846_hard_irq, ads7846_irq,
irq_flags, dev->driver->name, ts);
if (err && err != -EPROBE_DEFER && !pdata->irq_flags) {
dev_info(dev,
"trying pin change workaround on irq %d\n", spi->irq);
irq_flags |= IRQF_TRIGGER_RISING;
err = request_threaded_irq(spi->irq,
ads7846_hard_irq, ads7846_irq,
irq_flags, spi->dev.driver->name, ts);
err = devm_request_threaded_irq(dev, spi->irq,
ads7846_hard_irq, ads7846_irq,
irq_flags, dev->driver->name,
ts);
}
if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
goto err_disable_regulator;
dev_dbg(dev, "irq %d busy?\n", spi->irq);
return err;
}
err = ads784x_hwmon_register(spi, ts);
if (err)
goto err_free_irq;
return err;
dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
dev_info(dev, "touchscreen, irq %d\n", spi->irq);
/*
* Take a first sample, leaving nPENIRQ active and vREF off; avoid
* the touchscreen, in case it's not connected.
*/
if (ts->model == 7845)
ads7845_read12_ser(&spi->dev, PWRDOWN);
ads7845_read12_ser(dev, PWRDOWN);
else
(void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux));
(void) ads7846_read12_ser(dev, READ_12BIT_SER(vaux));
err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
err = devm_device_add_group(dev, &ads784x_attr_group);
if (err)
goto err_remove_hwmon;
return err;
err = input_register_device(input_dev);
if (err)
goto err_remove_attr_group;
return err;
device_init_wakeup(&spi->dev, pdata->wakeup);
device_init_wakeup(dev, pdata->wakeup);
/*
* If device does not carry platform data we must have allocated it
* when parsing DT data.
*/
if (!dev_get_platdata(&spi->dev))
devm_kfree(&spi->dev, (void *)pdata);
if (!dev_get_platdata(dev))
devm_kfree(dev, (void *)pdata);
return 0;
err_remove_attr_group:
sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
err_remove_hwmon:
ads784x_hwmon_unregister(spi, ts);
err_free_irq:
free_irq(spi->irq, ts);
err_disable_regulator:
regulator_disable(ts->reg);
err_put_regulator:
regulator_put(ts->reg);
err_free_gpio:
if (!ts->get_pendown_state)
gpio_free(ts->gpio_pendown);
err_cleanup_filter:
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);
err_free_mem:
input_free_device(input_dev);
kfree(packet);
kfree(ts);
return err;
}
static int ads7846_remove(struct spi_device *spi)
{
struct ads7846 *ts = spi_get_drvdata(spi);
sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
ads7846_disable(ts);
free_irq(ts->spi->irq, ts);
input_unregister_device(ts->input);
ads784x_hwmon_unregister(spi, ts);
regulator_put(ts->reg);
if (!ts->get_pendown_state) {
/*
* If we are not using specialized pendown method we must
* have been relying on gpio we set up ourselves.
*/
gpio_free(ts->gpio_pendown);
}
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);
kfree(ts->packet);
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
ads7846_stop(ts);
return 0;
}

View file

@ -1439,11 +1439,11 @@ static int elants_i2c_probe(struct i2c_client *client)
if (error)
return error;
error = devm_add_action(&client->dev, elants_i2c_power_off, ts);
error = devm_add_action_or_reset(&client->dev,
elants_i2c_power_off, ts);
if (error) {
dev_err(&client->dev,
"failed to install power off action: %d\n", error);
elants_i2c_power_off(ts);
return error;
}

View file

@ -14,20 +14,15 @@
#include <linux/kernel.h>
#include <linux/dmi.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/of.h>
#include <asm/unaligned.h>
#include "goodix.h"
#define GOODIX_GPIO_INT_NAME "irq"
#define GOODIX_GPIO_RST_NAME "reset"
@ -38,22 +33,11 @@
#define GOODIX_CONTACT_SIZE 8
#define GOODIX_MAX_CONTACT_SIZE 9
#define GOODIX_MAX_CONTACTS 10
#define GOODIX_MAX_KEYS 7
#define GOODIX_CONFIG_MIN_LENGTH 186
#define GOODIX_CONFIG_911_LENGTH 186
#define GOODIX_CONFIG_967_LENGTH 228
#define GOODIX_CONFIG_GT9X_LENGTH 240
#define GOODIX_CONFIG_MAX_LENGTH 240
/* Register defines */
#define GOODIX_REG_COMMAND 0x8040
#define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140
#define GOODIX_BUFFER_STATUS_READY BIT(7)
#define GOODIX_HAVE_KEY BIT(4)
@ -68,55 +52,11 @@
#define ACPI_GPIO_SUPPORT
#endif
struct goodix_ts_data;
enum goodix_irq_pin_access_method {
IRQ_PIN_ACCESS_NONE,
IRQ_PIN_ACCESS_GPIO,
IRQ_PIN_ACCESS_ACPI_GPIO,
IRQ_PIN_ACCESS_ACPI_METHOD,
};
struct goodix_chip_data {
u16 config_addr;
int config_len;
int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
void (*calc_config_checksum)(struct goodix_ts_data *ts);
};
struct goodix_chip_id {
const char *id;
const struct goodix_chip_data *data;
};
#define GOODIX_ID_MAX_LEN 4
struct goodix_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
const struct goodix_chip_data *chip;
struct touchscreen_properties prop;
unsigned int max_touch_num;
unsigned int int_trigger_type;
struct regulator *avdd28;
struct regulator *vddio;
struct gpio_desc *gpiod_int;
struct gpio_desc *gpiod_rst;
int gpio_count;
int gpio_int_idx;
char id[GOODIX_ID_MAX_LEN + 1];
u16 version;
const char *cfg_name;
bool reset_controller_at_probe;
bool load_cfg_from_disk;
struct completion firmware_loading_complete;
unsigned long irq_flags;
enum goodix_irq_pin_access_method irq_pin_access_method;
unsigned int contact_size;
u8 config[GOODIX_CONFIG_MAX_LENGTH];
unsigned short keymap[GOODIX_MAX_KEYS];
};
static int goodix_check_cfg_8(struct goodix_ts_data *ts,
const u8 *cfg, int len);
static int goodix_check_cfg_16(struct goodix_ts_data *ts,
@ -215,8 +155,7 @@ static const struct dmi_system_id inverted_x_screen[] = {
* @buf: raw write data buffer.
* @len: length of the buffer to write
*/
static int goodix_i2c_read(struct i2c_client *client,
u16 reg, u8 *buf, int len)
int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len)
{
struct i2c_msg msgs[2];
__be16 wbuf = cpu_to_be16(reg);
@ -233,7 +172,13 @@ static int goodix_i2c_read(struct i2c_client *client,
msgs[1].buf = buf;
ret = i2c_transfer(client->adapter, msgs, 2);
return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
if (ret >= 0)
ret = (ret == ARRAY_SIZE(msgs) ? 0 : -EIO);
if (ret)
dev_err(&client->dev, "Error reading %d bytes from 0x%04x: %d\n",
len, reg, ret);
return ret;
}
/**
@ -244,8 +189,7 @@ static int goodix_i2c_read(struct i2c_client *client,
* @buf: raw data buffer to write.
* @len: length of the buffer to write
*/
static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
unsigned len)
int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len)
{
u8 *addr_buf;
struct i2c_msg msg;
@ -265,11 +209,18 @@ static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
msg.len = len + 2;
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret >= 0)
ret = (ret == 1 ? 0 : -EIO);
kfree(addr_buf);
return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
if (ret)
dev_err(&client->dev, "Error writing %d bytes to 0x%04x: %d\n",
len, reg, ret);
return ret;
}
static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
{
return goodix_i2c_write(client, reg, &value, sizeof(value));
}
@ -308,11 +259,8 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
do {
error = goodix_i2c_read(ts->client, addr, data,
header_contact_keycode_size);
if (error) {
dev_err(&ts->client->dev, "I2C transfer error: %d\n",
error);
if (error)
return error;
}
if (data[0] & GOODIX_BUFFER_STATUS_READY) {
touch_num = data[0] & 0x0f;
@ -333,6 +281,11 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
return touch_num;
}
if (data[0] == 0 && ts->firmware_name) {
if (goodix_handle_fw_request(ts))
return 0;
}
usleep_range(1000, 2000); /* Poll every 1 - 2 ms */
} while (time_before(jiffies, max_timeout));
@ -435,9 +388,7 @@ static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
struct goodix_ts_data *ts = dev_id;
goodix_process_events(ts);
if (goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0) < 0)
dev_err(&ts->client->dev, "I2C write end_cmd error\n");
goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0);
return IRQ_HANDLED;
}
@ -553,7 +504,7 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
* @cfg: config firmware to write to device
* @len: config data length
*/
static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
{
int error;
@ -562,11 +513,9 @@ static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
return error;
error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg, len);
if (error) {
dev_err(&ts->client->dev, "Failed to write config data: %d",
error);
if (error)
return error;
}
dev_dbg(&ts->client->dev, "Config sent successfully.");
/* Let the firmware reconfigure itself, so sleep for 10ms */
@ -651,21 +600,66 @@ static int goodix_irq_direction_input(struct goodix_ts_data *ts)
return -EINVAL; /* Never reached */
}
static int goodix_int_sync(struct goodix_ts_data *ts)
int goodix_int_sync(struct goodix_ts_data *ts)
{
int error;
error = goodix_irq_direction_output(ts, 0);
if (error)
return error;
goto error;
msleep(50); /* T5: 50ms */
error = goodix_irq_direction_input(ts);
if (error)
return error;
goto error;
return 0;
error:
dev_err(&ts->client->dev, "Controller irq sync failed.\n");
return error;
}
/**
* goodix_reset_no_int_sync - Reset device, leaving interrupt line in output mode
*
* @ts: goodix_ts_data pointer
*/
int goodix_reset_no_int_sync(struct goodix_ts_data *ts)
{
int error;
/* begin select I2C slave addr */
error = gpiod_direction_output(ts->gpiod_rst, 0);
if (error)
goto error;
msleep(20); /* T2: > 10ms */
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
error = goodix_irq_direction_output(ts, ts->client->addr == 0x14);
if (error)
goto error;
usleep_range(100, 2000); /* T3: > 100us */
error = gpiod_direction_output(ts->gpiod_rst, 1);
if (error)
goto error;
usleep_range(6000, 10000); /* T4: > 5ms */
/* end select I2C slave addr */
error = gpiod_direction_input(ts->gpiod_rst);
if (error)
goto error;
return 0;
error:
dev_err(&ts->client->dev, "Controller reset failed.\n");
return error;
}
/**
@ -677,36 +671,11 @@ static int goodix_reset(struct goodix_ts_data *ts)
{
int error;
/* begin select I2C slave addr */
error = gpiod_direction_output(ts->gpiod_rst, 0);
error = goodix_reset_no_int_sync(ts);
if (error)
return error;
msleep(20); /* T2: > 10ms */
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
error = goodix_irq_direction_output(ts, ts->client->addr == 0x14);
if (error)
return error;
usleep_range(100, 2000); /* T3: > 100us */
error = gpiod_direction_output(ts->gpiod_rst, 1);
if (error)
return error;
usleep_range(6000, 10000); /* T4: > 5ms */
/* end select I2C slave addr */
error = gpiod_direction_input(ts->gpiod_rst);
if (error)
return error;
error = goodix_int_sync(ts);
if (error)
return error;
return 0;
return goodix_int_sync(ts);
}
#ifdef ACPI_GPIO_SUPPORT
@ -931,14 +900,19 @@ static void goodix_read_config(struct goodix_ts_data *ts)
int x_max, y_max;
int error;
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
ts->config, ts->chip->config_len);
if (error) {
dev_warn(&ts->client->dev, "Error reading config: %d\n",
error);
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
/*
* On controllers where we need to upload the firmware
* (controllers without flash) ts->config already has the config
* at this point and the controller itself does not have it yet!
*/
if (!ts->firmware_name) {
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
ts->config, ts->chip->config_len);
if (error) {
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
}
}
ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03;
@ -966,10 +940,8 @@ static int goodix_read_version(struct goodix_ts_data *ts)
char id_str[GOODIX_ID_MAX_LEN + 1];
error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf));
if (error) {
dev_err(&ts->client->dev, "read version failed: %d\n", error);
if (error)
return error;
}
memcpy(id_str, buf, GOODIX_ID_MAX_LEN);
id_str[GOODIX_ID_MAX_LEN] = 0;
@ -995,13 +967,10 @@ static int goodix_i2c_test(struct i2c_client *client)
u8 test;
while (retry++ < 2) {
error = goodix_i2c_read(client, GOODIX_REG_ID,
&test, 1);
error = goodix_i2c_read(client, GOODIX_REG_ID, &test, 1);
if (!error)
return 0;
dev_err(&client->dev, "i2c test failed attempt %d: %d\n",
retry, error);
msleep(20);
}
@ -1130,7 +1099,16 @@ static void goodix_config_cb(const struct firmware *cfg, void *ctx)
struct goodix_ts_data *ts = ctx;
int error;
if (cfg) {
if (ts->firmware_name) {
if (!cfg)
goto err_release_cfg;
error = goodix_check_cfg(ts, cfg->data, cfg->size);
if (error)
goto err_release_cfg;
memcpy(ts->config, cfg->data, cfg->size);
} else if (cfg) {
/* send device configuration to the firmware */
error = goodix_send_cfg(ts, cfg->data, cfg->size);
if (error)
@ -1156,6 +1134,7 @@ static int goodix_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct goodix_ts_data *ts;
const char *cfg_name;
int error;
dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
@ -1205,10 +1184,8 @@ reset:
if (ts->reset_controller_at_probe) {
/* reset the controller */
error = goodix_reset(ts);
if (error) {
dev_err(&client->dev, "Controller reset failed.\n");
if (error)
return error;
}
}
error = goodix_i2c_test(client);
@ -1223,20 +1200,27 @@ reset:
return error;
}
error = goodix_read_version(ts);
if (error) {
dev_err(&client->dev, "Read version failed.\n");
error = goodix_firmware_check(ts);
if (error)
return error;
error = goodix_read_version(ts);
if (error)
return error;
}
ts->chip = goodix_get_chip_data(ts->id);
if (ts->load_cfg_from_disk) {
/* update device config */
ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL,
"goodix_%s_cfg.bin", ts->id);
if (!ts->cfg_name)
return -ENOMEM;
error = device_property_read_string(&client->dev,
"goodix,config-name",
&cfg_name);
if (!error)
snprintf(ts->cfg_name, sizeof(ts->cfg_name),
"goodix/%s", cfg_name);
else
snprintf(ts->cfg_name, sizeof(ts->cfg_name),
"goodix_%s_cfg.bin", ts->id);
error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name,
&client->dev, GFP_KERNEL, ts,
@ -1286,6 +1270,9 @@ static int __maybe_unused goodix_suspend(struct device *dev)
/* Free IRQ as IRQ pin is used as output in the suspend sequence */
goodix_free_irq(ts);
/* Save reference (calibration) info if necessary */
goodix_save_bak_ref(ts);
/* Output LOW on the INT pin for 5 ms */
error = goodix_irq_direction_output(ts, 0);
if (error) {
@ -1298,7 +1285,6 @@ static int __maybe_unused goodix_suspend(struct device *dev)
error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND,
GOODIX_CMD_SCREEN_OFF);
if (error) {
dev_err(&ts->client->dev, "Screen off command failed\n");
goodix_irq_direction_input(ts);
goodix_request_irq(ts);
return -EAGAIN;
@ -1341,19 +1327,14 @@ static int __maybe_unused goodix_resume(struct device *dev)
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
&config_ver, 1);
if (error)
dev_warn(dev, "Error reading config version: %d, resetting controller\n",
error);
else if (config_ver != ts->config[0])
if (!error && config_ver != ts->config[0])
dev_info(dev, "Config version mismatch %d != %d, resetting controller\n",
config_ver, ts->config[0]);
if (error != 0 || config_ver != ts->config[0]) {
error = goodix_reset(ts);
if (error) {
dev_err(dev, "Controller reset failed.\n");
if (error)
return error;
}
error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
if (error)

View file

@ -0,0 +1,117 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __GOODIX_H__
#define __GOODIX_H__
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/regulator/consumer.h>
/* Register defines */
#define GOODIX_REG_MISCTL_DSP_CTL 0x4010
#define GOODIX_REG_MISCTL_SRAM_BANK 0x4048
#define GOODIX_REG_MISCTL_MEM_CD_EN 0x4049
#define GOODIX_REG_MISCTL_CACHE_EN 0x404B
#define GOODIX_REG_MISCTL_TMR0_EN 0x40B0
#define GOODIX_REG_MISCTL_SWRST 0x4180
#define GOODIX_REG_MISCTL_CPU_SWRST_PULSE 0x4184
#define GOODIX_REG_MISCTL_BOOTCTL 0x4190
#define GOODIX_REG_MISCTL_BOOT_OPT 0x4218
#define GOODIX_REG_MISCTL_BOOT_CTL 0x5094
#define GOODIX_REG_FW_SIG 0x8000
#define GOODIX_FW_SIG_LEN 10
#define GOODIX_REG_MAIN_CLK 0x8020
#define GOODIX_MAIN_CLK_LEN 6
#define GOODIX_REG_COMMAND 0x8040
#define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_REG_SW_WDT 0x8041
#define GOODIX_REG_REQUEST 0x8043
#define GOODIX_RQST_RESPONDED 0x00
#define GOODIX_RQST_CONFIG 0x01
#define GOODIX_RQST_BAK_REF 0x02
#define GOODIX_RQST_RESET 0x03
#define GOODIX_RQST_MAIN_CLOCK 0x04
/*
* Unknown request which gets send by the controller aprox.
* every 34 seconds once it is up and running.
*/
#define GOODIX_RQST_UNKNOWN 0x06
#define GOODIX_RQST_IDLE 0xFF
#define GOODIX_REG_STATUS 0x8044
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_REG_BAK_REF 0x99D0
#define GOODIX_ID_MAX_LEN 4
#define GOODIX_CONFIG_MAX_LENGTH 240
#define GOODIX_MAX_KEYS 7
enum goodix_irq_pin_access_method {
IRQ_PIN_ACCESS_NONE,
IRQ_PIN_ACCESS_GPIO,
IRQ_PIN_ACCESS_ACPI_GPIO,
IRQ_PIN_ACCESS_ACPI_METHOD,
};
struct goodix_ts_data;
struct goodix_chip_data {
u16 config_addr;
int config_len;
int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
void (*calc_config_checksum)(struct goodix_ts_data *ts);
};
struct goodix_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
const struct goodix_chip_data *chip;
const char *firmware_name;
struct touchscreen_properties prop;
unsigned int max_touch_num;
unsigned int int_trigger_type;
struct regulator *avdd28;
struct regulator *vddio;
struct gpio_desc *gpiod_int;
struct gpio_desc *gpiod_rst;
int gpio_count;
int gpio_int_idx;
char id[GOODIX_ID_MAX_LEN + 1];
char cfg_name[64];
u16 version;
bool reset_controller_at_probe;
bool load_cfg_from_disk;
struct completion firmware_loading_complete;
unsigned long irq_flags;
enum goodix_irq_pin_access_method irq_pin_access_method;
unsigned int contact_size;
u8 config[GOODIX_CONFIG_MAX_LENGTH];
unsigned short keymap[GOODIX_MAX_KEYS];
u8 main_clk[GOODIX_MAIN_CLK_LEN];
int bak_ref_len;
u8 *bak_ref;
};
int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);
int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len);
int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value);
int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len);
int goodix_int_sync(struct goodix_ts_data *ts);
int goodix_reset_no_int_sync(struct goodix_ts_data *ts);
int goodix_firmware_check(struct goodix_ts_data *ts);
bool goodix_handle_fw_request(struct goodix_ts_data *ts);
void goodix_save_bak_ref(struct goodix_ts_data *ts);
#endif

View file

@ -0,0 +1,427 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Goodix Touchscreen firmware upload support
*
* Copyright (c) 2021 Hans de Goede <hdegoede@redhat.com>
*
* This is a rewrite of gt9xx_update.c from the Allwinner H3 BSP which is:
* Copyright (c) 2010 - 2012 Goodix Technology.
* Author: andrew@goodix.com
*/
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include "goodix.h"
#define GOODIX_FW_HEADER_LENGTH sizeof(struct goodix_fw_header)
#define GOODIX_FW_SECTION_LENGTH 0x2000
#define GOODIX_FW_DSP_LENGTH 0x1000
#define GOODIX_FW_UPLOAD_ADDRESS 0xc000
#define GOODIX_CFG_LOC_HAVE_KEY 7
#define GOODIX_CFG_LOC_DRVA_NUM 27
#define GOODIX_CFG_LOC_DRVB_NUM 28
#define GOODIX_CFG_LOC_SENS_NUM 29
struct goodix_fw_header {
u8 hw_info[4];
u8 pid[8];
u8 vid[2];
} __packed;
static u16 goodix_firmware_checksum(const u8 *data, int size)
{
u16 checksum = 0;
int i;
for (i = 0; i < size; i += 2)
checksum += (data[i] << 8) + data[i + 1];
return checksum;
}
static int goodix_firmware_verify(struct device *dev, const struct firmware *fw)
{
const struct goodix_fw_header *fw_header;
size_t expected_size;
const u8 *data;
u16 checksum;
char buf[9];
expected_size = GOODIX_FW_HEADER_LENGTH + 4 * GOODIX_FW_SECTION_LENGTH +
GOODIX_FW_DSP_LENGTH;
if (fw->size != expected_size) {
dev_err(dev, "Firmware has wrong size, expected %zu got %zu\n",
expected_size, fw->size);
return -EINVAL;
}
data = fw->data + GOODIX_FW_HEADER_LENGTH;
checksum = goodix_firmware_checksum(data, 4 * GOODIX_FW_SECTION_LENGTH);
if (checksum) {
dev_err(dev, "Main firmware checksum error\n");
return -EINVAL;
}
data += 4 * GOODIX_FW_SECTION_LENGTH;
checksum = goodix_firmware_checksum(data, GOODIX_FW_DSP_LENGTH);
if (checksum) {
dev_err(dev, "DSP firmware checksum error\n");
return -EINVAL;
}
fw_header = (const struct goodix_fw_header *)fw->data;
dev_info(dev, "Firmware hardware info %02x%02x%02x%02x\n",
fw_header->hw_info[0], fw_header->hw_info[1],
fw_header->hw_info[2], fw_header->hw_info[3]);
/* pid is a 8 byte buffer containing a string, weird I know */
memcpy(buf, fw_header->pid, 8);
buf[8] = 0;
dev_info(dev, "Firmware PID: %s VID: %02x%02x\n", buf,
fw_header->vid[0], fw_header->vid[1]);
return 0;
}
static int goodix_enter_upload_mode(struct i2c_client *client)
{
int tries, error;
u8 val;
tries = 200;
do {
error = goodix_i2c_write_u8(client,
GOODIX_REG_MISCTL_SWRST, 0x0c);
if (error)
return error;
error = goodix_i2c_read(client,
GOODIX_REG_MISCTL_SWRST, &val, 1);
if (error)
return error;
if (val == 0x0c)
break;
} while (--tries);
if (!tries) {
dev_err(&client->dev, "Error could not hold ss51 & dsp\n");
return -EIO;
}
/* DSP_CK and DSP_ALU_CK PowerOn */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_DSP_CTL, 0x00);
if (error)
return error;
/* Disable watchdog */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_TMR0_EN, 0x00);
if (error)
return error;
/* Clear cache enable */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_CACHE_EN, 0x00);
if (error)
return error;
/* Set boot from SRAM */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOTCTL, 0x02);
if (error)
return error;
/* Software reboot */
error = goodix_i2c_write_u8(client,
GOODIX_REG_MISCTL_CPU_SWRST_PULSE, 0x01);
if (error)
return error;
/* Clear control flag */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOTCTL, 0x00);
if (error)
return error;
/* Set scramble */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOT_OPT, 0x00);
if (error)
return error;
/* Enable accessing code */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_MEM_CD_EN, 0x01);
if (error)
return error;
return 0;
}
static int goodix_start_firmware(struct i2c_client *client)
{
int error;
u8 val;
/* Init software watchdog */
error = goodix_i2c_write_u8(client, GOODIX_REG_SW_WDT, 0xaa);
if (error)
return error;
/* Release SS51 & DSP */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_SWRST, 0x00);
if (error)
return error;
error = goodix_i2c_read(client, GOODIX_REG_SW_WDT, &val, 1);
if (error)
return error;
/* The value we've written to SW_WDT should have been cleared now */
if (val == 0xaa) {
dev_err(&client->dev, "Error SW_WDT reg not cleared on fw startup\n");
return -EIO;
}
/* Re-init software watchdog */
error = goodix_i2c_write_u8(client, GOODIX_REG_SW_WDT, 0xaa);
if (error)
return error;
return 0;
}
static int goodix_firmware_upload(struct goodix_ts_data *ts)
{
const struct firmware *fw;
char fw_name[64];
const u8 *data;
int error;
snprintf(fw_name, sizeof(fw_name), "goodix/%s", ts->firmware_name);
error = request_firmware(&fw, fw_name, &ts->client->dev);
if (error) {
dev_err(&ts->client->dev, "Firmware request error %d\n", error);
return error;
}
error = goodix_firmware_verify(&ts->client->dev, fw);
if (error)
goto release;
error = goodix_reset_no_int_sync(ts);
if (error)
return error;
error = goodix_enter_upload_mode(ts->client);
if (error)
goto release;
/* Select SRAM bank 0 and upload section 1 & 2 */
error = goodix_i2c_write_u8(ts->client,
GOODIX_REG_MISCTL_SRAM_BANK, 0x00);
if (error)
goto release;
data = fw->data + GOODIX_FW_HEADER_LENGTH;
error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
data, 2 * GOODIX_FW_SECTION_LENGTH);
if (error)
goto release;
/* Select SRAM bank 1 and upload section 3 & 4 */
error = goodix_i2c_write_u8(ts->client,
GOODIX_REG_MISCTL_SRAM_BANK, 0x01);
if (error)
goto release;
data += 2 * GOODIX_FW_SECTION_LENGTH;
error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
data, 2 * GOODIX_FW_SECTION_LENGTH);
if (error)
goto release;
/* Select SRAM bank 2 and upload the DSP firmware */
error = goodix_i2c_write_u8(ts->client,
GOODIX_REG_MISCTL_SRAM_BANK, 0x02);
if (error)
goto release;
data += 2 * GOODIX_FW_SECTION_LENGTH;
error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
data, GOODIX_FW_DSP_LENGTH);
if (error)
goto release;
error = goodix_start_firmware(ts->client);
if (error)
goto release;
error = goodix_int_sync(ts);
release:
release_firmware(fw);
return error;
}
static int goodix_prepare_bak_ref(struct goodix_ts_data *ts)
{
u8 have_key, driver_num, sensor_num;
if (ts->bak_ref)
return 0; /* Already done */
have_key = (ts->config[GOODIX_CFG_LOC_HAVE_KEY] & 0x01);
driver_num = (ts->config[GOODIX_CFG_LOC_DRVA_NUM] & 0x1f) +
(ts->config[GOODIX_CFG_LOC_DRVB_NUM] & 0x1f);
if (have_key)
driver_num--;
sensor_num = (ts->config[GOODIX_CFG_LOC_SENS_NUM] & 0x0f) +
((ts->config[GOODIX_CFG_LOC_SENS_NUM] >> 4) & 0x0f);
dev_dbg(&ts->client->dev, "Drv %d Sen %d Key %d\n",
driver_num, sensor_num, have_key);
ts->bak_ref_len = (driver_num * (sensor_num - 2) + 2) * 2;
ts->bak_ref = devm_kzalloc(&ts->client->dev,
ts->bak_ref_len, GFP_KERNEL);
if (!ts->bak_ref)
return -ENOMEM;
/*
* The bak_ref array contains the backup of an array of (self/auto)
* calibration related values which the Android version of the driver
* stores on the filesystem so that it can be restored after reboot.
* The mainline kernel never writes directly to the filesystem like
* this, we always start will all the values which give a correction
* factor in approx. the -20 - +20 range (in 2s complement) set to 0.
*
* Note the touchscreen works fine without restoring the reference
* values after a reboot / power-cycle.
*
* The last 2 bytes are a 16 bits unsigned checksum which is expected
* to make the addition al all 16 bit unsigned values in the array add
* up to 1 (rather then the usual 0), so we must set the last byte to 1.
*/
ts->bak_ref[ts->bak_ref_len - 1] = 1;
return 0;
}
static int goodix_send_main_clock(struct goodix_ts_data *ts)
{
u32 main_clk = 54; /* Default main clock */
u8 checksum = 0;
int i;
device_property_read_u32(&ts->client->dev,
"goodix,main-clk", &main_clk);
for (i = 0; i < (GOODIX_MAIN_CLK_LEN - 1); i++) {
ts->main_clk[i] = main_clk;
checksum += main_clk;
}
/* The value of all bytes combines must be 0 */
ts->main_clk[GOODIX_MAIN_CLK_LEN - 1] = 256 - checksum;
return goodix_i2c_write(ts->client, GOODIX_REG_MAIN_CLK,
ts->main_clk, GOODIX_MAIN_CLK_LEN);
}
int goodix_firmware_check(struct goodix_ts_data *ts)
{
device_property_read_string(&ts->client->dev,
"firmware-name", &ts->firmware_name);
if (!ts->firmware_name)
return 0;
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
dev_err(&ts->client->dev, "Error no IRQ-pin access method, cannot upload fw.\n");
return -EINVAL;
}
dev_info(&ts->client->dev, "Touchscreen controller needs fw-upload\n");
ts->load_cfg_from_disk = true;
return goodix_firmware_upload(ts);
}
bool goodix_handle_fw_request(struct goodix_ts_data *ts)
{
int error;
u8 val;
error = goodix_i2c_read(ts->client, GOODIX_REG_REQUEST, &val, 1);
if (error)
return false;
switch (val) {
case GOODIX_RQST_RESPONDED:
/*
* If we read back our own last ack the IRQ was not for
* a request.
*/
return false;
case GOODIX_RQST_CONFIG:
error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
if (error)
return false;
break;
case GOODIX_RQST_BAK_REF:
error = goodix_prepare_bak_ref(ts);
if (error)
return false;
error = goodix_i2c_write(ts->client, GOODIX_REG_BAK_REF,
ts->bak_ref, ts->bak_ref_len);
if (error)
return false;
break;
case GOODIX_RQST_RESET:
error = goodix_firmware_upload(ts);
if (error)
return false;
break;
case GOODIX_RQST_MAIN_CLOCK:
error = goodix_send_main_clock(ts);
if (error)
return false;
break;
case GOODIX_RQST_UNKNOWN:
case GOODIX_RQST_IDLE:
break;
default:
dev_err_ratelimited(&ts->client->dev, "Unknown Request: 0x%02x\n", val);
}
/* Ack the request */
goodix_i2c_write_u8(ts->client,
GOODIX_REG_REQUEST, GOODIX_RQST_RESPONDED);
return true;
}
void goodix_save_bak_ref(struct goodix_ts_data *ts)
{
int error;
u8 val;
if (!ts->firmware_name)
return;
error = goodix_i2c_read(ts->client, GOODIX_REG_STATUS, &val, 1);
if (error)
return;
if (!(val & 0x80))
return;
error = goodix_i2c_read(ts->client, GOODIX_REG_BAK_REF,
ts->bak_ref, ts->bak_ref_len);
if (error) {
memset(ts->bak_ref, 0, ts->bak_ref_len);
ts->bak_ref[ts->bak_ref_len - 1] = 1;
}
}

View file

@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/crc-ccitt.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/ihex.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
@ -12,7 +14,7 @@
#include <linux/slab.h>
#include <asm/unaligned.h>
#define ILI2XXX_POLL_PERIOD 20
#define ILI2XXX_POLL_PERIOD 15
#define ILI210X_DATA_SIZE 64
#define ILI211X_DATA_SIZE 43
@ -22,8 +24,23 @@
/* Touchscreen commands */
#define REG_TOUCHDATA 0x10
#define REG_PANEL_INFO 0x20
#define REG_FIRMWARE_VERSION 0x40
#define REG_PROTOCOL_VERSION 0x42
#define REG_KERNEL_VERSION 0x61
#define REG_IC_BUSY 0x80
#define REG_IC_BUSY_NOT_BUSY 0x50
#define REG_GET_MODE 0xc0
#define REG_GET_MODE_AP 0x5a
#define REG_GET_MODE_BL 0x55
#define REG_SET_MODE_AP 0xc1
#define REG_SET_MODE_BL 0xc2
#define REG_WRITE_DATA 0xc3
#define REG_WRITE_ENABLE 0xc4
#define REG_READ_DATA_CRC 0xc7
#define REG_CALIBRATE 0xcc
#define ILI251X_FW_FILENAME "ilitek/ili251x.bin"
struct ili2xxx_chip {
int (*read_reg)(struct i2c_client *client, u8 reg,
void *buf, size_t len);
@ -35,6 +52,7 @@ struct ili2xxx_chip {
unsigned int max_touches;
unsigned int resolution;
bool has_calibrate_reg;
bool has_firmware_proto;
bool has_pressure_reg;
};
@ -44,6 +62,10 @@ struct ili210x {
struct gpio_desc *reset_gpio;
struct touchscreen_properties prop;
const struct ili2xxx_chip *chip;
u8 version_firmware[8];
u8 version_kernel[5];
u8 version_proto[2];
u8 ic_mode[2];
bool stop;
};
@ -202,15 +224,17 @@ static const struct ili2xxx_chip ili212x_chip = {
.has_calibrate_reg = true,
};
static int ili251x_read_reg(struct i2c_client *client,
u8 reg, void *buf, size_t len)
static int ili251x_read_reg_common(struct i2c_client *client,
u8 reg, void *buf, size_t len,
unsigned int delay)
{
int error;
int ret;
ret = i2c_master_send(client, &reg, 1);
if (ret == 1) {
usleep_range(5000, 5500);
if (delay)
usleep_range(delay, delay + 500);
ret = i2c_master_recv(client, buf, len);
if (ret == len)
@ -222,12 +246,18 @@ static int ili251x_read_reg(struct i2c_client *client,
return ret;
}
static int ili251x_read_reg(struct i2c_client *client,
u8 reg, void *buf, size_t len)
{
return ili251x_read_reg_common(client, reg, buf, len, 5000);
}
static int ili251x_read_touch_data(struct i2c_client *client, u8 *data)
{
int error;
error = ili251x_read_reg(client, REG_TOUCHDATA,
data, ILI251X_DATA_SIZE1);
error = ili251x_read_reg_common(client, REG_TOUCHDATA,
data, ILI251X_DATA_SIZE1, 0);
if (!error && data[0] == 2) {
error = i2c_master_recv(client, data + ILI251X_DATA_SIZE1,
ILI251X_DATA_SIZE2);
@ -268,6 +298,7 @@ static const struct ili2xxx_chip ili251x_chip = {
.continue_polling = ili251x_check_continue_polling,
.max_touches = 10,
.has_calibrate_reg = true,
.has_firmware_proto = true,
.has_pressure_reg = true,
};
@ -303,10 +334,13 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data)
const struct ili2xxx_chip *chip = priv->chip;
u8 touchdata[ILI210X_DATA_SIZE] = { 0 };
bool keep_polling;
ktime_t time_next;
s64 time_delta;
bool touch;
int error;
do {
time_next = ktime_add_ms(ktime_get(), ILI2XXX_POLL_PERIOD);
error = chip->get_touch_data(client, touchdata);
if (error) {
dev_err(&client->dev,
@ -316,13 +350,201 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data)
touch = ili210x_report_events(priv, touchdata);
keep_polling = chip->continue_polling(touchdata, touch);
if (keep_polling)
msleep(ILI2XXX_POLL_PERIOD);
if (keep_polling) {
time_delta = ktime_us_delta(time_next, ktime_get());
if (time_delta > 0)
usleep_range(time_delta, time_delta + 1000);
}
} while (!priv->stop && keep_polling);
return IRQ_HANDLED;
}
static int ili251x_firmware_update_resolution(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u16 resx, resy;
u8 rs[10];
int error;
/* The firmware update blob might have changed the resolution. */
error = priv->chip->read_reg(client, REG_PANEL_INFO, &rs, sizeof(rs));
if (error)
return error;
resx = le16_to_cpup((__le16 *)rs);
resy = le16_to_cpup((__le16 *)(rs + 2));
/* The value reported by the firmware is invalid. */
if (!resx || resx == 0xffff || !resy || resy == 0xffff)
return -EINVAL;
input_abs_set_max(priv->input, ABS_X, resx - 1);
input_abs_set_max(priv->input, ABS_Y, resy - 1);
input_abs_set_max(priv->input, ABS_MT_POSITION_X, resx - 1);
input_abs_set_max(priv->input, ABS_MT_POSITION_Y, resy - 1);
return 0;
}
static ssize_t ili251x_firmware_update_firmware_version(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
u8 fw[8];
/* Get firmware version */
error = priv->chip->read_reg(client, REG_FIRMWARE_VERSION,
&fw, sizeof(fw));
if (!error)
memcpy(priv->version_firmware, fw, sizeof(fw));
return error;
}
static ssize_t ili251x_firmware_update_kernel_version(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
u8 kv[5];
/* Get kernel version */
error = priv->chip->read_reg(client, REG_KERNEL_VERSION,
&kv, sizeof(kv));
if (!error)
memcpy(priv->version_kernel, kv, sizeof(kv));
return error;
}
static ssize_t ili251x_firmware_update_protocol_version(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
u8 pv[2];
/* Get protocol version */
error = priv->chip->read_reg(client, REG_PROTOCOL_VERSION,
&pv, sizeof(pv));
if (!error)
memcpy(priv->version_proto, pv, sizeof(pv));
return error;
}
static ssize_t ili251x_firmware_update_ic_mode(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
u8 md[2];
/* Get chip boot mode */
error = priv->chip->read_reg(client, REG_GET_MODE, &md, sizeof(md));
if (!error)
memcpy(priv->ic_mode, md, sizeof(md));
return error;
}
static int ili251x_firmware_update_cached_state(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
if (!priv->chip->has_firmware_proto)
return 0;
/* Wait for firmware to boot and stabilize itself. */
msleep(200);
/* Firmware does report valid information. */
error = ili251x_firmware_update_resolution(dev);
if (error)
return error;
error = ili251x_firmware_update_firmware_version(dev);
if (error)
return error;
error = ili251x_firmware_update_kernel_version(dev);
if (error)
return error;
error = ili251x_firmware_update_protocol_version(dev);
if (error)
return error;
error = ili251x_firmware_update_ic_mode(dev);
if (error)
return error;
return 0;
}
static ssize_t ili251x_firmware_version_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 *fw = priv->version_firmware;
return sysfs_emit(buf, "%02x%02x.%02x%02x.%02x%02x.%02x%02x\n",
fw[0], fw[1], fw[2], fw[3],
fw[4], fw[5], fw[6], fw[7]);
}
static DEVICE_ATTR(firmware_version, 0444, ili251x_firmware_version_show, NULL);
static ssize_t ili251x_kernel_version_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 *kv = priv->version_kernel;
return sysfs_emit(buf, "%02x.%02x.%02x.%02x.%02x\n",
kv[0], kv[1], kv[2], kv[3], kv[4]);
}
static DEVICE_ATTR(kernel_version, 0444, ili251x_kernel_version_show, NULL);
static ssize_t ili251x_protocol_version_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 *pv = priv->version_proto;
return sysfs_emit(buf, "%02x.%02x\n", pv[0], pv[1]);
}
static DEVICE_ATTR(protocol_version, 0444, ili251x_protocol_version_show, NULL);
static ssize_t ili251x_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 *md = priv->ic_mode;
char *mode = "AP";
if (md[0] == REG_GET_MODE_AP) /* Application Mode */
mode = "AP";
else if (md[0] == REG_GET_MODE_BL) /* BootLoader Mode */
mode = "BL";
else /* Unknown Mode */
mode = "??";
return sysfs_emit(buf, "%02x.%02x:%s\n", md[0], md[1], mode);
}
static DEVICE_ATTR(mode, 0444, ili251x_mode_show, NULL);
static ssize_t ili210x_calibrate(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@ -349,24 +571,333 @@ static ssize_t ili210x_calibrate(struct device *dev,
}
static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
static int ili251x_firmware_to_buffer(const struct firmware *fw,
u8 **buf, u16 *ac_end, u16 *df_end)
{
const struct ihex_binrec *rec;
u32 fw_addr, fw_last_addr = 0;
u16 fw_len;
u8 *fw_buf;
int error;
/*
* The firmware ihex blob can never be bigger than 64 kiB, so make this
* simple -- allocate a 64 kiB buffer, iterate over the ihex blob records
* once, copy them all into this buffer at the right locations, and then
* do all operations on this linear buffer.
*/
fw_buf = kzalloc(SZ_64K, GFP_KERNEL);
if (!fw_buf)
return -ENOMEM;
rec = (const struct ihex_binrec *)fw->data;
while (rec) {
fw_addr = be32_to_cpu(rec->addr);
fw_len = be16_to_cpu(rec->len);
/* The last 32 Byte firmware block can be 0xffe0 */
if (fw_addr + fw_len > SZ_64K || fw_addr > SZ_64K - 32) {
error = -EFBIG;
goto err_big;
}
/* Find the last address before DF start address, that is AC end */
if (fw_addr == 0xf000)
*ac_end = fw_last_addr;
fw_last_addr = fw_addr + fw_len;
memcpy(fw_buf + fw_addr, rec->data, fw_len);
rec = ihex_next_binrec(rec);
}
/* DF end address is the last address in the firmware blob */
*df_end = fw_addr + fw_len;
*buf = fw_buf;
return 0;
err_big:
kfree(fw_buf);
return error;
}
/* Switch mode between Application and BootLoader */
static int ili251x_switch_ic_mode(struct i2c_client *client, u8 cmd_mode)
{
struct ili210x *priv = i2c_get_clientdata(client);
u8 cmd_wren[3] = { REG_WRITE_ENABLE, 0x5a, 0xa5 };
u8 md[2];
int error;
error = priv->chip->read_reg(client, REG_GET_MODE, md, sizeof(md));
if (error)
return error;
/* Mode already set */
if ((cmd_mode == REG_SET_MODE_AP && md[0] == REG_GET_MODE_AP) ||
(cmd_mode == REG_SET_MODE_BL && md[0] == REG_GET_MODE_BL))
return 0;
/* Unlock writes */
error = i2c_master_send(client, cmd_wren, sizeof(cmd_wren));
if (error != sizeof(cmd_wren))
return -EINVAL;
mdelay(20);
/* Select mode (BootLoader or Application) */
error = i2c_master_send(client, &cmd_mode, 1);
if (error != 1)
return -EINVAL;
mdelay(200); /* Reboot into bootloader takes a lot of time ... */
/* Read back mode */
error = priv->chip->read_reg(client, REG_GET_MODE, md, sizeof(md));
if (error)
return error;
/* Check if mode is correct now. */
if ((cmd_mode == REG_SET_MODE_AP && md[0] == REG_GET_MODE_AP) ||
(cmd_mode == REG_SET_MODE_BL && md[0] == REG_GET_MODE_BL))
return 0;
return -EINVAL;
}
static int ili251x_firmware_busy(struct i2c_client *client)
{
struct ili210x *priv = i2c_get_clientdata(client);
int error, i = 0;
u8 data;
do {
/* The read_reg already contains suitable delay */
error = priv->chip->read_reg(client, REG_IC_BUSY, &data, 1);
if (error)
return error;
if (i++ == 100000)
return -ETIMEDOUT;
} while (data != REG_IC_BUSY_NOT_BUSY);
return 0;
}
static int ili251x_firmware_write_to_ic(struct device *dev, u8 *fwbuf,
u16 start, u16 end, u8 dataflash)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 cmd_crc = REG_READ_DATA_CRC;
u8 crcrb[4] = { 0 };
u8 fw_data[33];
u16 fw_addr;
int error;
/*
* The DF (dataflash) needs 2 bytes offset for unknown reasons,
* the AC (application) has 2 bytes CRC16-CCITT at the end.
*/
u16 crc = crc_ccitt(0, fwbuf + start + (dataflash ? 2 : 0),
end - start - 2);
/* Unlock write to either AC (application) or DF (dataflash) area */
u8 cmd_wr[10] = {
REG_WRITE_ENABLE, 0x5a, 0xa5, dataflash,
(end >> 16) & 0xff, (end >> 8) & 0xff, end & 0xff,
(crc >> 16) & 0xff, (crc >> 8) & 0xff, crc & 0xff
};
error = i2c_master_send(client, cmd_wr, sizeof(cmd_wr));
if (error != sizeof(cmd_wr))
return -EINVAL;
error = ili251x_firmware_busy(client);
if (error)
return error;
for (fw_addr = start; fw_addr < end; fw_addr += 32) {
fw_data[0] = REG_WRITE_DATA;
memcpy(&(fw_data[1]), fwbuf + fw_addr, 32);
error = i2c_master_send(client, fw_data, 33);
if (error != sizeof(fw_data))
return error;
error = ili251x_firmware_busy(client);
if (error)
return error;
}
error = i2c_master_send(client, &cmd_crc, 1);
if (error != 1)
return -EINVAL;
error = ili251x_firmware_busy(client);
if (error)
return error;
error = priv->chip->read_reg(client, REG_READ_DATA_CRC,
&crcrb, sizeof(crcrb));
if (error)
return error;
/* Check CRC readback */
if ((crcrb[0] != (crc & 0xff)) || crcrb[1] != ((crc >> 8) & 0xff))
return -EINVAL;
return 0;
}
static int ili251x_firmware_reset(struct i2c_client *client)
{
u8 cmd_reset[2] = { 0xf2, 0x01 };
int error;
error = i2c_master_send(client, cmd_reset, sizeof(cmd_reset));
if (error != sizeof(cmd_reset))
return -EINVAL;
return ili251x_firmware_busy(client);
}
static void ili251x_hardware_reset(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
/* Reset the controller */
gpiod_set_value_cansleep(priv->reset_gpio, 1);
usleep_range(10000, 15000);
gpiod_set_value_cansleep(priv->reset_gpio, 0);
msleep(300);
}
static ssize_t ili210x_firmware_update_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
const char *fwname = ILI251X_FW_FILENAME;
const struct firmware *fw;
u16 ac_end, df_end;
u8 *fwbuf;
int error;
int i;
error = request_ihex_firmware(&fw, fwname, dev);
if (error) {
dev_err(dev, "Failed to request firmware %s, error=%d\n",
fwname, error);
return error;
}
error = ili251x_firmware_to_buffer(fw, &fwbuf, &ac_end, &df_end);
release_firmware(fw);
if (error)
return error;
/*
* Disable touchscreen IRQ, so that we would not get spurious touch
* interrupt during firmware update, and so that the IRQ handler won't
* trigger and interfere with the firmware update. There is no bit in
* the touch controller to disable the IRQs during update, so we have
* to do it this way here.
*/
disable_irq(client->irq);
dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
ili251x_hardware_reset(dev);
error = ili251x_firmware_reset(client);
if (error)
goto exit;
/* This may not succeed on first try, so re-try a few times. */
for (i = 0; i < 5; i++) {
error = ili251x_switch_ic_mode(client, REG_SET_MODE_BL);
if (!error)
break;
}
if (error)
goto exit;
dev_dbg(dev, "IC is now in BootLoader mode\n");
msleep(200); /* The bootloader seems to need some time too. */
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0xf000, df_end, 1);
if (error) {
dev_err(dev, "DF firmware update failed, error=%d\n", error);
goto exit;
}
dev_dbg(dev, "DataFlash firmware written\n");
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0x2000, ac_end, 0);
if (error) {
dev_err(dev, "AC firmware update failed, error=%d\n", error);
goto exit;
}
dev_dbg(dev, "Application firmware written\n");
/* This may not succeed on first try, so re-try a few times. */
for (i = 0; i < 5; i++) {
error = ili251x_switch_ic_mode(client, REG_SET_MODE_AP);
if (!error)
break;
}
if (error)
goto exit;
dev_dbg(dev, "IC is now in Application mode\n");
error = ili251x_firmware_update_cached_state(dev);
if (error)
goto exit;
error = count;
exit:
ili251x_hardware_reset(dev);
dev_dbg(dev, "Firmware update ended, error=%i\n", error);
enable_irq(client->irq);
kfree(fwbuf);
return error;
}
static DEVICE_ATTR(firmware_update, 0200, NULL, ili210x_firmware_update_store);
static struct attribute *ili210x_attributes[] = {
&dev_attr_calibrate.attr,
&dev_attr_firmware_update.attr,
&dev_attr_firmware_version.attr,
&dev_attr_kernel_version.attr,
&dev_attr_protocol_version.attr,
&dev_attr_mode.attr,
NULL,
};
static umode_t ili210x_calibrate_visible(struct kobject *kobj,
static umode_t ili210x_attributes_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = kobj_to_dev(kobj);
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
return priv->chip->has_calibrate_reg ? attr->mode : 0;
/* Calibrate is present on all ILI2xxx which have calibrate register */
if (attr == &dev_attr_calibrate.attr)
return priv->chip->has_calibrate_reg ? attr->mode : 0;
/* Firmware/Kernel/Protocol/BootMode is implememted only for ILI251x */
if (!priv->chip->has_firmware_proto)
return 0;
return attr->mode;
}
static const struct attribute_group ili210x_attr_group = {
.attrs = ili210x_attributes,
.is_visible = ili210x_calibrate_visible,
.is_visible = ili210x_attributes_visible,
};
static void ili210x_power_down(void *data)
@ -449,6 +980,12 @@ static int ili210x_i2c_probe(struct i2c_client *client,
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0);
if (priv->chip->has_pressure_reg)
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xa, 0, 0);
error = ili251x_firmware_update_cached_state(dev);
if (error) {
dev_err(dev, "Unable to cache firmware information, err: %d\n",
error);
return error;
}
touchscreen_parse_properties(input, true, &priv->prop);
error = input_mt_init_slots(input, priv->chip->max_touches,

View file

@ -37,6 +37,7 @@
#define RM_CMD_BOOT_READ 0x44 /* send wait bl data ready*/
#define RM_BOOT_RDY 0xFF /* bl data ready */
#define RM_BOOT_CMD_READHWID 0x0E /* read hwid */
/* I2C main commands */
#define RM_CMD_QUERY_BANK 0x2B
@ -290,6 +291,44 @@ static int raydium_i2c_sw_reset(struct i2c_client *client)
return 0;
}
static int raydium_i2c_query_ts_bootloader_info(struct raydium_data *ts)
{
struct i2c_client *client = ts->client;
static const u8 get_hwid[] = { RM_BOOT_CMD_READHWID,
0x10, 0xc0, 0x01, 0x00, 0x04, 0x00 };
u8 rbuf[5] = { 0 };
u32 hw_ver;
int error;
error = raydium_i2c_send(client, RM_CMD_BOOT_WRT,
get_hwid, sizeof(get_hwid));
if (error) {
dev_err(&client->dev, "WRT HWID command failed: %d\n", error);
return error;
}
error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, rbuf, 1);
if (error) {
dev_err(&client->dev, "Ack HWID command failed: %d\n", error);
return error;
}
error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, rbuf, sizeof(rbuf));
if (error) {
dev_err(&client->dev, "Read HWID command failed: %d (%4ph)\n",
error, rbuf + 1);
hw_ver = 0xffffffffUL;
} else {
hw_ver = get_unaligned_be32(rbuf + 1);
}
ts->info.hw_ver = cpu_to_le32(hw_ver);
ts->info.main_ver = 0xff;
ts->info.sub_ver = 0xff;
return error;
}
static int raydium_i2c_query_ts_info(struct raydium_data *ts)
{
struct i2c_client *client = ts->client;
@ -388,13 +427,10 @@ static int raydium_i2c_initialize(struct raydium_data *ts)
if (error)
ts->boot_mode = RAYDIUM_TS_BLDR;
if (ts->boot_mode == RAYDIUM_TS_BLDR) {
ts->info.hw_ver = cpu_to_le32(0xffffffffUL);
ts->info.main_ver = 0xff;
ts->info.sub_ver = 0xff;
} else {
if (ts->boot_mode == RAYDIUM_TS_BLDR)
raydium_i2c_query_ts_bootloader_info(ts);
else
raydium_i2c_query_ts_info(ts);
}
return error;
}
@ -1082,11 +1118,11 @@ static int raydium_i2c_probe(struct i2c_client *client,
if (error)
return error;
error = devm_add_action(&client->dev, raydium_i2c_power_off, ts);
error = devm_add_action_or_reset(&client->dev,
raydium_i2c_power_off, ts);
if (error) {
dev_err(&client->dev,
"failed to install power off action: %d\n", error);
raydium_i2c_power_off(ts);
return error;
}
@ -1218,7 +1254,7 @@ static SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
raydium_i2c_suspend, raydium_i2c_resume);
static const struct i2c_device_id raydium_i2c_id[] = {
{ "raydium_i2c" , 0 },
{ "raydium_i2c", 0 },
{ "rm32380", 0 },
{ /* sentinel */ }
};

View file

@ -92,7 +92,7 @@ static int st1232_ts_wait_ready(struct st1232_ts_data *ts)
unsigned int retries;
int error;
for (retries = 10; retries; retries--) {
for (retries = 100; retries; retries--) {
error = st1232_ts_read_data(ts, REG_STATUS, 1);
if (!error) {
switch (ts->read_buf[0]) {
@ -389,6 +389,7 @@ static struct i2c_driver st1232_ts_driver = {
.driver = {
.name = ST1232_TS_NAME,
.of_match_table = st1232_ts_dt_ids,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &st1232_ts_pm_ops,
},
};

View file

@ -45,7 +45,9 @@ static int tsc2004_probe(struct i2c_client *i2c,
static int tsc2004_remove(struct i2c_client *i2c)
{
return tsc200x_remove(&i2c->dev);
tsc200x_remove(&i2c->dev);
return 0;
}
static const struct i2c_device_id tsc2004_idtable[] = {

View file

@ -66,7 +66,9 @@ static int tsc2005_probe(struct spi_device *spi)
static int tsc2005_remove(struct spi_device *spi)
{
return tsc200x_remove(&spi->dev);
tsc200x_remove(&spi->dev);
return 0;
}
#ifdef CONFIG_OF

View file

@ -577,15 +577,13 @@ disable_regulator:
}
EXPORT_SYMBOL_GPL(tsc200x_probe);
int tsc200x_remove(struct device *dev)
void tsc200x_remove(struct device *dev)
{
struct tsc200x *ts = dev_get_drvdata(dev);
sysfs_remove_group(&dev->kobj, &tsc200x_attr_group);
regulator_disable(ts->vio);
return 0;
}
EXPORT_SYMBOL_GPL(tsc200x_remove);

View file

@ -74,6 +74,6 @@ extern const struct dev_pm_ops tsc200x_pm_ops;
int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
struct regmap *regmap,
int (*tsc200x_cmd)(struct device *dev, u8 cmd));
int tsc200x_remove(struct device *dev);
void tsc200x_remove(struct device *dev);
#endif

View file

@ -6,6 +6,7 @@
* <tobita.tatsunosuke@wacom.co.jp>
*/
#include <linux/bits.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/i2c.h>
@ -14,6 +15,15 @@
#include <linux/interrupt.h>
#include <asm/unaligned.h>
/* Bitmasks (for data[3]) */
#define WACOM_TIP_SWITCH BIT(0)
#define WACOM_BARREL_SWITCH BIT(1)
#define WACOM_ERASER BIT(2)
#define WACOM_INVERT BIT(3)
#define WACOM_BARREL_SWITCH_2 BIT(4)
#define WACOM_IN_PROXIMITY BIT(5)
/* Registers */
#define WACOM_CMD_QUERY0 0x04
#define WACOM_CMD_QUERY1 0x00
#define WACOM_CMD_QUERY2 0x33
@ -99,19 +109,19 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
if (error < 0)
goto out;
tsw = data[3] & 0x01;
ers = data[3] & 0x04;
f1 = data[3] & 0x02;
f2 = data[3] & 0x10;
tsw = data[3] & WACOM_TIP_SWITCH;
ers = data[3] & WACOM_ERASER;
f1 = data[3] & WACOM_BARREL_SWITCH;
f2 = data[3] & WACOM_BARREL_SWITCH_2;
x = le16_to_cpup((__le16 *)&data[4]);
y = le16_to_cpup((__le16 *)&data[6]);
pressure = le16_to_cpup((__le16 *)&data[8]);
if (!wac_i2c->prox)
wac_i2c->tool = (data[3] & 0x0c) ?
wac_i2c->tool = (data[3] & (WACOM_ERASER | WACOM_INVERT)) ?
BTN_TOOL_RUBBER : BTN_TOOL_PEN;
wac_i2c->prox = data[3] & 0x20;
wac_i2c->prox = data[3] & WACOM_IN_PROXIMITY;
input_report_key(input, BTN_TOUCH, tsw || ers);
input_report_key(input, wac_i2c->tool, wac_i2c->prox);

View file

@ -294,6 +294,7 @@ config GTP
config AMT
tristate "Automatic Multicast Tunneling (AMT)"
depends on INET && IP_MULTICAST
depends on IPV6 || !IPV6
select NET_UDP_TUNNEL
help
This allows one to create AMT(Automatic Multicast Tunneling)

View file

@ -12,7 +12,6 @@
#include <linux/igmp.h>
#include <linux/workqueue.h>
#include <net/net_namespace.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/udp_tunnel.h>
@ -23,7 +22,6 @@
#include <linux/security.h>
#include <net/gro_cells.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/if_inet6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
@ -2767,7 +2765,7 @@ static int amt_err_lookup(struct sock *sk, struct sk_buff *skb)
rcu_read_lock_bh();
amt = rcu_dereference_sk_user_data(sk);
if (!amt)
goto drop;
goto out;
if (amt->mode != AMT_MODE_GATEWAY)
goto drop;
@ -2789,6 +2787,7 @@ static int amt_err_lookup(struct sock *sk, struct sk_buff *skb)
default:
goto drop;
}
out:
rcu_read_unlock_bh();
return 0;
drop:
@ -3259,8 +3258,10 @@ static int __init amt_init(void)
goto unregister_notifier;
amt_wq = alloc_workqueue("amt", WQ_UNBOUND, 1);
if (!amt_wq)
if (!amt_wq) {
err = -ENOMEM;
goto rtnl_unregister;
}
spin_lock_init(&source_gc_lock);
spin_lock_bh(&source_gc_lock);
@ -3285,7 +3286,7 @@ static void __exit amt_fini(void)
{
rtnl_link_unregister(&amt_link_ops);
unregister_netdevice_notifier(&amt_notifier_block);
flush_delayed_work(&source_gc_wq);
cancel_delayed_work(&source_gc_wq);
__amt_source_gc_work();
destroy_workqueue(amt_wq);
}

View file

@ -108,15 +108,15 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf)
}
static SLAVE_ATTR_RO(ad_partner_oper_port_state);
static const struct slave_attribute *slave_attrs[] = {
&slave_attr_state,
&slave_attr_mii_status,
&slave_attr_link_failure_count,
&slave_attr_perm_hwaddr,
&slave_attr_queue_id,
&slave_attr_ad_aggregator_id,
&slave_attr_ad_actor_oper_port_state,
&slave_attr_ad_partner_oper_port_state,
static const struct attribute *slave_attrs[] = {
&slave_attr_state.attr,
&slave_attr_mii_status.attr,
&slave_attr_link_failure_count.attr,
&slave_attr_perm_hwaddr.attr,
&slave_attr_queue_id.attr,
&slave_attr_ad_aggregator_id.attr,
&slave_attr_ad_actor_oper_port_state.attr,
&slave_attr_ad_partner_oper_port_state.attr,
NULL
};
@ -137,24 +137,10 @@ const struct sysfs_ops slave_sysfs_ops = {
int bond_sysfs_slave_add(struct slave *slave)
{
const struct slave_attribute **a;
int err;
for (a = slave_attrs; *a; ++a) {
err = sysfs_create_file(&slave->kobj, &((*a)->attr));
if (err) {
kobject_put(&slave->kobj);
return err;
}
}
return 0;
return sysfs_create_files(&slave->kobj, slave_attrs);
}
void bond_sysfs_slave_del(struct slave *slave)
{
const struct slave_attribute **a;
for (a = slave_attrs; *a; ++a)
sysfs_remove_file(&slave->kobj, &((*a)->attr));
sysfs_remove_files(&slave->kobj, slave_attrs);
}

View file

@ -1092,7 +1092,7 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
err = mcp251xfd_chip_rx_int_enable(priv);
if (err)
return err;
goto out_chip_stop;
err = mcp251xfd_chip_ecc_init(priv);
if (err)
@ -2290,8 +2290,10 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
* check will fail, too. So leave IRQ handler
* directly.
*/
if (priv->can.state == CAN_STATE_BUS_OFF)
if (priv->can.state == CAN_STATE_BUS_OFF) {
can_rx_offload_threaded_irq_finish(&priv->offload);
return IRQ_HANDLED;
}
}
handled = IRQ_HANDLED;

View file

@ -664,7 +664,7 @@ int es58x_rx_err_msg(struct net_device *netdev, enum es58x_err error,
struct can_device_stats *can_stats = &can->can_stats;
struct can_frame *cf = NULL;
struct sk_buff *skb;
int ret;
int ret = 0;
if (!netif_running(netdev)) {
if (net_ratelimit())
@ -823,8 +823,6 @@ int es58x_rx_err_msg(struct net_device *netdev, enum es58x_err error,
can->state = CAN_STATE_BUS_OFF;
can_bus_off(netdev);
ret = can->do_set_mode(netdev, CAN_MODE_STOP);
if (ret)
return ret;
}
break;
@ -881,7 +879,7 @@ int es58x_rx_err_msg(struct net_device *netdev, enum es58x_err error,
ES58X_EVENT_BUSOFF, timestamp);
}
return 0;
return ret;
}
/**

View file

@ -841,14 +841,14 @@ static int pcan_usb_start(struct peak_usb_device *dev)
pdev->bec.rxerr = 0;
pdev->bec.txerr = 0;
/* be notified on error counter changes (if requested by user) */
if (dev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
err = pcan_usb_set_err_frame(dev, PCAN_USB_BERR_MASK);
if (err)
netdev_warn(dev->netdev,
"Asking for BERR reporting error %u\n",
err);
}
/* always ask the device for BERR reporting, to be able to switch from
* WARNING to PASSIVE state
*/
err = pcan_usb_set_err_frame(dev, PCAN_USB_BERR_MASK);
if (err)
netdev_warn(dev->netdev,
"Asking for BERR reporting error %u\n",
err);
/* if revision greater than 3, can put silent mode on/off */
if (dev->device_rev > 3) {
@ -883,6 +883,11 @@ static int pcan_usb_init(struct peak_usb_device *dev)
return err;
}
dev_info(dev->netdev->dev.parent,
"PEAK-System %s adapter hwrev %u serial %08X (%u channel)\n",
pcan_usb.name, dev->device_rev, serial_number,
pcan_usb.ctrl_count);
/* Since rev 4.1, PCAN-USB is able to make single-shot as well as
* looped back frames.
*/
@ -896,11 +901,6 @@ static int pcan_usb_init(struct peak_usb_device *dev)
"Firmware update available. Please contact support@peak-system.com\n");
}
dev_info(dev->netdev->dev.parent,
"PEAK-System %s adapter hwrev %u serial %08X (%u channel)\n",
pcan_usb.name, dev->device_rev, serial_number,
pcan_usb.ctrl_count);
return 0;
}
@ -986,7 +986,6 @@ const struct peak_usb_adapter pcan_usb = {
.device_id = PCAN_USB_PRODUCT_ID,
.ctrl_count = 1,
.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_CC_LEN8_DLC,
.clock = {
.freq = PCAN_USB_CRYSTAL_HZ / 2,

View file

@ -640,7 +640,10 @@ static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
unsigned long *mask,
struct phylink_link_state *state)
{
if (port == 0 || port == 9 || port == 10) {
bool is_6191x =
chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X;
if (((port == 0 || port == 9) && !is_6191x) || port == 10) {
phylink_set(mask, 10000baseT_Full);
phylink_set(mask, 10000baseKR_Full);
phylink_set(mask, 10000baseCR_Full);

View file

@ -1370,12 +1370,12 @@ out:
static bool felix_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type)
{
u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
u32 tstamp_lo = OCELOT_SKB_CB(skb)->tstamp_lo;
struct skb_shared_hwtstamps *shhwtstamps;
struct ocelot *ocelot = ds->priv;
u32 tstamp_lo, tstamp_hi;
struct timespec64 ts;
u64 tstamp, val;
u32 tstamp_hi;
u64 tstamp;
/* If the "no XTR IRQ" workaround is in use, tell DSA to defer this skb
* for RX timestamping. Then free it, and poll for its copy through
@ -1390,9 +1390,6 @@ static bool felix_rxtstamp(struct dsa_switch *ds, int port,
ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
tstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
ocelot_xfh_get_rew_val(extraction, &val);
tstamp_lo = (u32)val;
tstamp_hi = tstamp >> 32;
if ((tstamp & 0xffffffff) < tstamp_lo)
tstamp_hi--;

Some files were not shown because too many files have changed in this diff Show more