diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-11-27 17:45:38 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-11-27 17:45:38 -0800 |
commit | bf65fa1dcae4aa4a65f9cdcab45aa013b2054ab3 (patch) | |
tree | 8f4c98ec456ace005c132623e38b996fbc6af04e | |
parent | ab2fa693c905f2dd6ad435082fa8c175a1ddbd23 (diff) | |
download | ltsi-kernel-bf65fa1dcae4aa4a65f9cdcab45aa013b2054ab3.tar.gz |
More altera and a "misc" patch
11 files changed, 2097 insertions, 14 deletions
diff --git a/patches.altera/0001-nios2-Export-get_cycles.patch b/patches.altera/0001-nios2-Export-get_cycles.patch new file mode 100644 index 00000000000000..6e6c3d94c31700 --- /dev/null +++ b/patches.altera/0001-nios2-Export-get_cycles.patch @@ -0,0 +1,38 @@ +From b0d9b942747467745e6035caa5272a6c919141c2 Mon Sep 17 00:00:00 2001 +From: Herbert Xu <herbert@gondor.apana.org.au> +Date: Tue, 9 Jun 2015 12:46:46 +0800 +Subject: [PATCH 1/9] nios2: Export get_cycles + +nios2 is the only architecture that does not inline get_cycles +and does not export it. This breaks crypto as it uses get_cycles +in a number of modules. + +Reported-by: Guenter Roeck <linux@roeck-us.net> +Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> +--- + arch/nios2/kernel/time.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c +index 7f4547418ee1..be186a75f622 100644 +--- a/arch/nios2/kernel/time.c ++++ b/arch/nios2/kernel/time.c +@@ -8,6 +8,7 @@ + * for more details. + */ + ++#include <linux/export.h> + #include <linux/interrupt.h> + #include <linux/clockchips.h> + #include <linux/clocksource.h> +@@ -106,6 +107,7 @@ cycles_t get_cycles(void) + { + return nios2_timer_read(&nios2_cs.cs); + } ++EXPORT_SYMBOL(get_cycles); + + static void nios2_timer_start(struct nios2_timer *timer) + { +-- +2.6.2 + diff --git a/patches.altera/0002-nios2-check-number-of-timer-instances.patch b/patches.altera/0002-nios2-check-number-of-timer-instances.patch new file mode 100644 index 00000000000000..047757cd990a71 --- /dev/null +++ b/patches.altera/0002-nios2-check-number-of-timer-instances.patch @@ -0,0 +1,48 @@ +From f842e15b14fca61686a1d6488f9edaedecb302ee Mon Sep 17 00:00:00 2001 +From: Ley Foon Tan <lftan@altera.com> +Date: Wed, 24 Jun 2015 17:52:44 +0800 +Subject: [PATCH 2/9] nios2: check number of timer instances + +Display error message if number of timers is less than 2. + +Signed-off-by: Ley Foon Tan <lftan@altera.com> +--- + arch/nios2/kernel/time.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c +index be186a75f622..9e3cc8a40ee9 100644 +--- a/arch/nios2/kernel/time.c ++++ b/arch/nios2/kernel/time.c +@@ -19,7 +19,9 @@ + #include <linux/io.h> + #include <linux/slab.h> + +-#define ALTERA_TIMER_STATUS_REG 0 ++#define ALTR_TIMER_COMPATIBLE "altr,timer-1.0" ++ ++#define ALTERA_TIMER_STATUS_REG 0 + #define ALTERA_TIMER_CONTROL_REG 4 + #define ALTERA_TIMER_PERIODL_REG 8 + #define ALTERA_TIMER_PERIODH_REG 12 +@@ -304,7 +306,16 @@ void read_persistent_clock(struct timespec *ts) + + void __init time_init(void) + { ++ struct device_node *np; ++ int count = 0; ++ ++ for_each_compatible_node(np, NULL, ALTR_TIMER_COMPATIBLE) ++ count++; ++ ++ if (count < 2) ++ panic("%d timer is found, it needs 2 timers in system\n", count); ++ + clocksource_of_init(); + } + +-CLOCKSOURCE_OF_DECLARE(nios2_timer, "altr,timer-1.0", nios2_time_init); ++CLOCKSOURCE_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); +-- +2.6.2 + diff --git a/patches.altera/0003-nios2-time-Migrate-to-new-set-state-interface.patch b/patches.altera/0003-nios2-time-Migrate-to-new-set-state-interface.patch new file mode 100644 index 00000000000000..675af3d75546ec --- /dev/null +++ b/patches.altera/0003-nios2-time-Migrate-to-new-set-state-interface.patch @@ -0,0 +1,113 @@ +From be2926f60f84ffc870e5b57c255e9a5d236c7cbf Mon Sep 17 00:00:00 2001 +From: Viresh Kumar <viresh.kumar@linaro.org> +Date: Tue, 18 Aug 2015 13:59:28 +0800 +Subject: [PATCH 3/9] nios2/time: Migrate to new 'set-state' interface + +Migrate nios2 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. + +This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. + +Cc: Ley Foon Tan <lftan@altera.com> +Cc: Tobias Klauser <tklauser@distanz.ch> +Cc: Herbert Xu <herbert@gondor.apana.org.au> +Cc: Dmitry Torokhov <dtor@chromium.org> +Cc: nios2-dev@lists.rocketboards.org +Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> +Acked-by: Ley Foon Tan <lftan@altera.com> +--- + arch/nios2/kernel/time.c | 49 ++++++++++++++++++++++++++++-------------------- + 1 file changed, 29 insertions(+), 20 deletions(-) + +diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c +index 9e3cc8a40ee9..bbc3f9157f9c 100644 +--- a/arch/nios2/kernel/time.c ++++ b/arch/nios2/kernel/time.c +@@ -130,7 +130,7 @@ static void nios2_timer_stop(struct nios2_timer *timer) + } + + static void nios2_timer_config(struct nios2_timer *timer, unsigned long period, +- enum clock_event_mode mode) ++ bool periodic) + { + u16 ctrl; + +@@ -148,7 +148,7 @@ static void nios2_timer_config(struct nios2_timer *timer, unsigned long period, + timer_writew(timer, period >> 16, ALTERA_TIMER_PERIODH_REG); + + ctrl |= ALTERA_TIMER_CONTROL_START_MSK | ALTERA_TIMER_CONTROL_ITO_MSK; +- if (mode == CLOCK_EVT_MODE_PERIODIC) ++ if (periodic) + ctrl |= ALTERA_TIMER_CONTROL_CONT_MSK; + else + ctrl &= ~ALTERA_TIMER_CONTROL_CONT_MSK; +@@ -160,32 +160,38 @@ static int nios2_timer_set_next_event(unsigned long delta, + { + struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); + +- nios2_timer_config(&nios2_ced->timer, delta, evt->mode); ++ nios2_timer_config(&nios2_ced->timer, delta, false); + + return 0; + } + +-static void nios2_timer_set_mode(enum clock_event_mode mode, +- struct clock_event_device *evt) ++static int nios2_timer_shutdown(struct clock_event_device *evt) ++{ ++ struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); ++ struct nios2_timer *timer = &nios2_ced->timer; ++ ++ nios2_timer_stop(timer); ++ return 0; ++} ++ ++static int nios2_timer_set_periodic(struct clock_event_device *evt) + { + unsigned long period; + struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); + struct nios2_timer *timer = &nios2_ced->timer; + +- switch (mode) { +- case CLOCK_EVT_MODE_PERIODIC: +- period = DIV_ROUND_UP(timer->freq, HZ); +- nios2_timer_config(timer, period, CLOCK_EVT_MODE_PERIODIC); +- break; +- case CLOCK_EVT_MODE_ONESHOT: +- case CLOCK_EVT_MODE_UNUSED: +- case CLOCK_EVT_MODE_SHUTDOWN: +- nios2_timer_stop(timer); +- break; +- case CLOCK_EVT_MODE_RESUME: +- nios2_timer_start(timer); +- break; +- } ++ period = DIV_ROUND_UP(timer->freq, HZ); ++ nios2_timer_config(timer, period, true); ++ return 0; ++} ++ ++static int nios2_timer_resume(struct clock_event_device *evt) ++{ ++ struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); ++ struct nios2_timer *timer = &nios2_ced->timer; ++ ++ nios2_timer_start(timer); ++ return 0; + } + + irqreturn_t timer_interrupt(int irq, void *dev_id) +@@ -218,7 +224,10 @@ static struct nios2_clockevent_dev nios2_ce = { + .rating = 250, + .shift = 32, + .set_next_event = nios2_timer_set_next_event, +- .set_mode = nios2_timer_set_mode, ++ .set_state_shutdown = nios2_timer_shutdown, ++ .set_state_periodic = nios2_timer_set_periodic, ++ .set_state_oneshot = nios2_timer_shutdown, ++ .tick_resume = nios2_timer_resume, + }, + }; + +-- +2.6.2 + diff --git a/patches.altera/0004-nios2-fixed-variable-imm16-to-s16.patch b/patches.altera/0004-nios2-fixed-variable-imm16-to-s16.patch new file mode 100644 index 00000000000000..baa96df37877dc --- /dev/null +++ b/patches.altera/0004-nios2-fixed-variable-imm16-to-s16.patch @@ -0,0 +1,29 @@ +From 503c5aa3817e2c566ecc6fd6dae4e20d7d4da259 Mon Sep 17 00:00:00 2001 +From: Bernd Weiberg <bernd.weiberg@siemens.com> +Date: Fri, 4 Sep 2015 17:03:03 +0800 +Subject: [PATCH 4/9] nios2: fixed variable imm16 to s16 + +Fxid variable imm16 to s16 instead of u16, offset might be negative. + +Signed-off-by: Bernd Weiberg <bernd.weiberg@siemens.com> +Signed-off-by: Ley Foon Tan <lftan@altera.com> +--- + arch/nios2/kernel/misaligned.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/nios2/kernel/misaligned.c b/arch/nios2/kernel/misaligned.c +index 4e5907a0cabe..89fe0b6ee339 100644 +--- a/arch/nios2/kernel/misaligned.c ++++ b/arch/nios2/kernel/misaligned.c +@@ -71,7 +71,7 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) + u32 isn, addr, val; + int in_kernel; + u8 a, b, d0, d1, d2, d3; +- u16 imm16; ++ s16 imm16; + unsigned int fault; + + /* back up one instruction */ +-- +2.6.2 + diff --git a/patches.altera/0005-nios2-remove-unused-statistic-counters.patch b/patches.altera/0005-nios2-remove-unused-statistic-counters.patch new file mode 100644 index 00000000000000..6a957025026107 --- /dev/null +++ b/patches.altera/0005-nios2-remove-unused-statistic-counters.patch @@ -0,0 +1,112 @@ +From 4fda2c0976d428ba8b33c733e8439c3846161dd6 Mon Sep 17 00:00:00 2001 +From: Bernd Weiberg <bernd.weiberg@siemens.com> +Date: Fri, 4 Sep 2015 16:59:45 +0800 +Subject: [PATCH 5/9] nios2: remove unused statistic counters + +Removed some statistic counters to improve the performance of the handler. + +Signed-off-by: Bernd Weiberg <bernd.weiberg@siemens.com> +Signed-off-by: Ley Foon Tan <lftan@altera.com> +--- + arch/nios2/kernel/misaligned.c | 18 ------------------ + 1 file changed, 18 deletions(-) + +diff --git a/arch/nios2/kernel/misaligned.c b/arch/nios2/kernel/misaligned.c +index 89fe0b6ee339..23e0544e117c 100644 +--- a/arch/nios2/kernel/misaligned.c ++++ b/arch/nios2/kernel/misaligned.c +@@ -32,8 +32,6 @@ + #define INST_STW 0x15 + #define INST_LDW 0x17 + +-static unsigned long ma_user, ma_kern, ma_skipped, ma_half, ma_word; +- + static unsigned int ma_usermode; + #define UM_WARN 0x01 + #define UM_FIXUP 0x02 +@@ -53,7 +51,6 @@ static int reg_offsets[32]; + static inline u32 get_reg_val(struct pt_regs *fp, int reg) + { + u8 *p = ((u8 *)fp) + reg_offsets[reg]; +- + return *(u32 *)p; + } + +@@ -78,7 +75,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) + fp->ea -= 4; + + if (fixup_exception(fp)) { +- ma_skipped++; + return; + } + +@@ -103,18 +99,11 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) + fault |= __get_user(d1, (u8 *)(addr+1)); + val = (d1 << 8) | d0; + put_reg_val(fp, b, val); +- ma_half++; + break; + case INST_STH: + val = get_reg_val(fp, b); + d1 = val >> 8; + d0 = val >> 0; +- +- pr_debug("sth: ra=%d (%08x) rb=%d (%08x), imm16 %04x addr %08x val %08x\n", +- a, get_reg_val(fp, a), +- b, get_reg_val(fp, b), +- imm16, addr, val); +- + if (in_kernel) { + *(u8 *)(addr+0) = d0; + *(u8 *)(addr+1) = d1; +@@ -122,14 +111,12 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) + fault |= __put_user(d0, (u8 *)(addr+0)); + fault |= __put_user(d1, (u8 *)(addr+1)); + } +- ma_half++; + break; + case INST_LDH: + fault |= __get_user(d0, (u8 *)(addr+0)); + fault |= __get_user(d1, (u8 *)(addr+1)); + val = (short)((d1 << 8) | d0); + put_reg_val(fp, b, val); +- ma_half++; + break; + case INST_STW: + val = get_reg_val(fp, b); +@@ -148,7 +135,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) + fault |= __put_user(d2, (u8 *)(addr+2)); + fault |= __put_user(d3, (u8 *)(addr+3)); + } +- ma_word++; + break; + case INST_LDW: + fault |= __get_user(d0, (u8 *)(addr+0)); +@@ -157,7 +143,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) + fault |= __get_user(d3, (u8 *)(addr+3)); + val = (d3 << 24) | (d2 << 16) | (d1 << 8) | d0; + put_reg_val(fp, b, val); +- ma_word++; + break; + } + } +@@ -186,7 +171,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) + * note exception and skip bad instruction (return) + */ + if (in_kernel) { +- ma_kern++; + fp->ea += 4; + + if (ma_usermode & KM_WARN) { +@@ -200,8 +184,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) + return; + } + +- ma_user++; +- + /* + * user mode - + * possibly warn, +-- +2.6.2 + diff --git a/patches.altera/0006-nios2-Add-Max10-device-tree.patch b/patches.altera/0006-nios2-Add-Max10-device-tree.patch new file mode 100644 index 00000000000000..358f2d78856dbb --- /dev/null +++ b/patches.altera/0006-nios2-Add-Max10-device-tree.patch @@ -0,0 +1,272 @@ +From 1ed6d08bf81a5feef41266d49ca6ee93bfd85f86 Mon Sep 17 00:00:00 2001 +From: Chee Nouk Phoon <cnphoon@altera.com> +Date: Tue, 8 Sep 2015 18:07:44 +0800 +Subject: [PATCH 6/9] nios2: Add Max10 device tree + +Max10 is a FPGA device. This patch adds Nios2 support for Max10. +This device tree is based on Max10 hardware reference design. + +Signed-off-by: Chee Nouk Phoon <cnphoon@altera.com> +Signed-off-by: Ley Foon Tan <lftan@altera.com> +--- + arch/nios2/boot/dts/10m50_devboard.dts | 248 +++++++++++++++++++++++++++++++++ + 1 file changed, 248 insertions(+) + create mode 100755 arch/nios2/boot/dts/10m50_devboard.dts + +diff --git a/arch/nios2/boot/dts/10m50_devboard.dts b/arch/nios2/boot/dts/10m50_devboard.dts +new file mode 100755 +index 000000000000..3e411c644824 +--- /dev/null ++++ b/arch/nios2/boot/dts/10m50_devboard.dts +@@ -0,0 +1,248 @@ ++/* ++ * Copyright (C) 2015 Altera Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++/dts-v1/; ++ ++/ { ++ model = "Altera NiosII Max10"; ++ compatible = "altr,niosii-max10"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu: cpu@0 { ++ device_type = "cpu"; ++ compatible = "altr,nios2-1.1"; ++ reg = <0x00000000>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ altr,exception-addr = <0xc8000120>; ++ altr,fast-tlb-miss-addr = <0xc0000100>; ++ altr,has-div = <1>; ++ altr,has-initda = <1>; ++ altr,has-mmu = <1>; ++ altr,has-mul = <1>; ++ altr,implementation = "fast"; ++ altr,pid-num-bits = <8>; ++ altr,reset-addr = <0xd4000000>; ++ altr,tlb-num-entries = <256>; ++ altr,tlb-num-ways = <16>; ++ altr,tlb-ptr-sz = <8>; ++ clock-frequency = <75000000>; ++ dcache-line-size = <32>; ++ dcache-size = <32768>; ++ icache-line-size = <32>; ++ icache-size = <32768>; ++ }; ++ }; ++ ++ memory { ++ device_type = "memory"; ++ reg = <0x08000000 0x08000000>, ++ <0x00000000 0x00000400>; ++ }; ++ ++ sopc0: sopc@0 { ++ device_type = "soc"; ++ ranges; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "altr,avalon", "simple-bus"; ++ bus-frequency = <75000000>; ++ ++ jtag_uart: serial@18001530 { ++ compatible = "altr,juart-1.0"; ++ reg = <0x18001530 0x00000008>; ++ interrupt-parent = <&cpu>; ++ interrupts = <7>; ++ }; ++ ++ a_16550_uart_0: serial@18001600 { ++ compatible = "altr,16550-FIFO32", "ns16550a"; ++ reg = <0x18001600 0x00000200>; ++ interrupt-parent = <&cpu>; ++ interrupts = <1>; ++ auto-flow-control = <1>; ++ clock-frequency = <50000000>; ++ fifo-size = <32>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ }; ++ ++ sysid: sysid@18001528 { ++ compatible = "altr,sysid-1.0"; ++ reg = <0x18001528 0x00000008>; ++ id = <4207856382>; ++ timestamp = <1431309290>; ++ }; ++ ++ rgmii_0_eth_tse_0: ethernet@400 { ++ compatible = "altr,tse-msgdma-1.0", "altr,tse-1.0"; ++ reg = <0x00000400 0x00000400>, ++ <0x00000820 0x00000020>, ++ <0x00000800 0x00000020>, ++ <0x000008c0 0x00000008>, ++ <0x00000840 0x00000020>, ++ <0x00000860 0x00000020>; ++ reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc"; ++ interrupt-parent = <&cpu>; ++ interrupts = <2 3>; ++ interrupt-names = "rx_irq", "tx_irq"; ++ rx-fifo-depth = <8192>; ++ tx-fifo-depth = <8192>; ++ address-bits = <48>; ++ max-frame-size = <1518>; ++ local-mac-address = [00 00 00 00 00 00]; ++ altr,has-supplementary-unicast; ++ altr,enable-sup-addr = <1>; ++ altr,has-hash-multicast-filter; ++ altr,enable-hash = <1>; ++ phy-mode = "rgmii-id"; ++ phy-handle = <&phy0>; ++ rgmii_0_eth_tse_0_mdio: mdio { ++ compatible = "altr,tse-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ phy0: ethernet-phy@0 { ++ reg = <0>; ++ device_type = "ethernet-phy"; ++ }; ++ }; ++ }; ++ ++ enet_pll: clock@0 { ++ compatible = "altr,pll-1.0"; ++ #clock-cells = <1>; ++ ++ enet_pll_c0: enet_pll_c0 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <125000000>; ++ clock-output-names = "enet_pll-c0"; ++ }; ++ ++ enet_pll_c1: enet_pll_c1 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <25000000>; ++ clock-output-names = "enet_pll-c1"; ++ }; ++ ++ enet_pll_c2: enet_pll_c2 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <2500000>; ++ clock-output-names = "enet_pll-c2"; ++ }; ++ }; ++ ++ sys_pll: clock@1 { ++ compatible = "altr,pll-1.0"; ++ #clock-cells = <1>; ++ ++ sys_pll_c0: sys_pll_c0 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <100000000>; ++ clock-output-names = "sys_pll-c0"; ++ }; ++ ++ sys_pll_c1: sys_pll_c1 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <50000000>; ++ clock-output-names = "sys_pll-c1"; ++ }; ++ ++ sys_pll_c2: sys_pll_c2 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <75000000>; ++ clock-output-names = "sys_pll-c2"; ++ }; ++ }; ++ ++ sys_clk_timer: timer@18001440 { ++ compatible = "altr,timer-1.0"; ++ reg = <0x18001440 0x00000020>; ++ interrupt-parent = <&cpu>; ++ interrupts = <0>; ++ clock-frequency = <75000000>; ++ }; ++ ++ led_pio: gpio@180014d0 { ++ compatible = "altr,pio-1.0"; ++ reg = <0x180014d0 0x00000010>; ++ altr,gpio-bank-width = <4>; ++ resetvalue = <15>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ }; ++ ++ button_pio: gpio@180014c0 { ++ compatible = "altr,pio-1.0"; ++ reg = <0x180014c0 0x00000010>; ++ interrupt-parent = <&cpu>; ++ interrupts = <6>; ++ altr,gpio-bank-width = <3>; ++ altr,interrupt-type = <2>; ++ edge_type = <1>; ++ level_trigger = <0>; ++ resetvalue = <0>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ }; ++ ++ sys_clk_timer_1: timer@880 { ++ compatible = "altr,timer-1.0"; ++ reg = <0x00000880 0x00000020>; ++ interrupt-parent = <&cpu>; ++ interrupts = <5>; ++ clock-frequency = <75000000>; ++ }; ++ ++ fpga_leds: leds { ++ compatible = "gpio-leds"; ++ ++ led_fpga0: fpga0 { ++ label = "fpga_led0"; ++ gpios = <&led_pio 0 1>; ++ }; ++ ++ led_fpga1: fpga1 { ++ label = "fpga_led1"; ++ gpios = <&led_pio 1 1>; ++ }; ++ ++ led_fpga2: fpga2 { ++ label = "fpga_led2"; ++ gpios = <&led_pio 2 1>; ++ }; ++ ++ led_fpga3: fpga3 { ++ label = "fpga_led3"; ++ gpios = <&led_pio 3 1>; ++ }; ++ }; ++ }; ++ ++ chosen { ++ bootargs = "debug console=ttyS0,115200"; ++ }; ++}; +-- +2.6.2 + diff --git a/patches.altera/0007-nios2-add-Max10-defconfig.patch b/patches.altera/0007-nios2-add-Max10-defconfig.patch new file mode 100644 index 00000000000000..d8e96180ed3779 --- /dev/null +++ b/patches.altera/0007-nios2-add-Max10-defconfig.patch @@ -0,0 +1,105 @@ +From f8a56cef689111e5bec8f600b7748ef15ec5f0f2 Mon Sep 17 00:00:00 2001 +From: Chee Nouk Phoon <cnphoon@altera.com> +Date: Tue, 8 Sep 2015 18:08:56 +0800 +Subject: [PATCH 7/9] nios2: add Max10 defconfig + +Max10 is a FPGA device. This patch adds defconfig based on Max10 hardware +reference design. Design is intended to run on Max10 development kit. + +Signed-off-by: Chee Nouk Phoon <cnphoon@altera.com> +Signed-off-by: Ley Foon Tan <lftan@altera.com> +--- + arch/nios2/configs/10m50_defconfig | 81 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 81 insertions(+) + create mode 100755 arch/nios2/configs/10m50_defconfig + +diff --git a/arch/nios2/configs/10m50_defconfig b/arch/nios2/configs/10m50_defconfig +new file mode 100755 +index 000000000000..8b2a30b3b34f +--- /dev/null ++++ b/arch/nios2/configs/10m50_defconfig +@@ -0,0 +1,81 @@ ++CONFIG_SYSVIPC=y ++CONFIG_NO_HZ_IDLE=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_SYSCTL_SYSCALL=y ++# CONFIG_ELF_CORE is not set ++# CONFIG_EPOLL is not set ++# CONFIG_SIGNALFD is not set ++# CONFIG_TIMERFD is not set ++# CONFIG_EVENTFD is not set ++# CONFIG_SHMEM is not set ++# CONFIG_AIO is not set ++CONFIG_EMBEDDED=y ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_NIOS2_MEM_BASE=0x8000000 ++CONFIG_NIOS2_HW_MUL_SUPPORT=y ++CONFIG_NIOS2_HW_DIV_SUPPORT=y ++CONFIG_CUSTOM_CACHE_SETTINGS=y ++CONFIG_NIOS2_DCACHE_SIZE=0x8000 ++CONFIG_NIOS2_ICACHE_SIZE=0x8000 ++# CONFIG_NIOS2_CMDLINE_IGNORE_DTB is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++# CONFIG_IPV6 is not set ++# CONFIG_WIRELESS is not set ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_FW_LOADER is not set ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_CFI_AMDSTD=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_NETDEVICES=y ++CONFIG_ALTERA_TSE=y ++CONFIG_MARVELL_PHY=y ++# CONFIG_WLAN is not set ++# CONFIG_INPUT_MOUSE is not set ++# CONFIG_SERIO_SERPORT is not set ++# CONFIG_VT is not set ++CONFIG_SERIAL_8250=y ++# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_OF_PLATFORM=y ++CONFIG_SERIAL_ALTERA_JTAGUART=y ++# CONFIG_HW_RANDOM is not set ++CONFIG_GPIOLIB=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_GPIO_ALTERA=y ++# CONFIG_HWMON is not set ++# CONFIG_USB_SUPPORT is not set ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++# CONFIG_DNOTIFY is not set ++# CONFIG_INOTIFY_USER is not set ++CONFIG_JFFS2_FS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3_ACL=y ++CONFIG_ROOT_NFS=y ++CONFIG_SUNRPC_DEBUG=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_ENABLE_WARN_DEPRECATED is not set +-- +2.6.2 + diff --git a/patches.altera/0008-nios2-Fix-unused-variable-warning.patch b/patches.altera/0008-nios2-Fix-unused-variable-warning.patch new file mode 100644 index 00000000000000..2d86f8f993cd48 --- /dev/null +++ b/patches.altera/0008-nios2-Fix-unused-variable-warning.patch @@ -0,0 +1,36 @@ +From 577da9b93378b056215d239ba2216401bfd5a069 Mon Sep 17 00:00:00 2001 +From: Marek Vasut <marex@denx.de> +Date: Wed, 30 Sep 2015 22:06:46 +0800 +Subject: [PATCH 8/9] nios2: Fix unused variable warning + +Fix the following compiler splat by adding __maybe_unused annotation to +the variable. Using this particular annotation has the least ugly impact +on the code compared to using ifdeffery. + +arch/nios2/kernel/setup.c: In function 'nios2_boot_init': +arch/nios2/kernel/setup.c:107:7: warning: unused variable 'cmdline_passed' [-Wunused-variable] + char cmdline_passed[COMMAND_LINE_SIZE] = { 0, }; + ^ + +Signed-off-by: Marek Vasut <marex@denx.de> +Acked-by: Ley Foon Tan <lftan@altera.com> +--- + arch/nios2/kernel/setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/nios2/kernel/setup.c b/arch/nios2/kernel/setup.c +index b101a43d3c5a..a4ff86d58d5c 100644 +--- a/arch/nios2/kernel/setup.c ++++ b/arch/nios2/kernel/setup.c +@@ -104,7 +104,7 @@ asmlinkage void __init nios2_boot_init(unsigned r4, unsigned r5, unsigned r6, + unsigned r7) + { + unsigned dtb_passed = 0; +- char cmdline_passed[COMMAND_LINE_SIZE] = { 0, }; ++ char cmdline_passed[COMMAND_LINE_SIZE] __maybe_unused = { 0, }; + + #if defined(CONFIG_NIOS2_PASS_CMDLINE) + if (r4 == 0x534f494e) { /* r4 is magic NIOS */ +-- +2.6.2 + diff --git a/patches.altera/0009-nios2-Switch-to-generic-__xchg.patch b/patches.altera/0009-nios2-Switch-to-generic-__xchg.patch new file mode 100644 index 00000000000000..109ba8570d7758 --- /dev/null +++ b/patches.altera/0009-nios2-Switch-to-generic-__xchg.patch @@ -0,0 +1,76 @@ +From 90df4ef19e6dfb7521e05ece60546677491c9e32 Mon Sep 17 00:00:00 2001 +From: Marek Vasut <marex@denx.de> +Date: Wed, 30 Sep 2015 22:08:00 +0800 +Subject: [PATCH 9/9] nios2: Switch to generic __xchg() + +The generic __xchg() implementation present in asm-generic/cmpxchg.h is +correct on nios2 and even generates the same code. Switch to this generic +implementation to trim down the amount of ad-hoc copies of the code. + +Signed-off-by: Marek Vasut <marex@denx.de> +Acked-by: Ley Foon Tan <lftan@altera.com> +--- + arch/nios2/include/asm/cmpxchg.h | 47 ---------------------------------------- + 1 file changed, 47 deletions(-) + +diff --git a/arch/nios2/include/asm/cmpxchg.h b/arch/nios2/include/asm/cmpxchg.h +index 85938711542d..a7978f14d157 100644 +--- a/arch/nios2/include/asm/cmpxchg.h ++++ b/arch/nios2/include/asm/cmpxchg.h +@@ -9,53 +9,6 @@ + #ifndef _ASM_NIOS2_CMPXCHG_H + #define _ASM_NIOS2_CMPXCHG_H + +-#include <linux/irqflags.h> +- +-#define xchg(ptr, x) \ +- ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) +- +-struct __xchg_dummy { unsigned long a[100]; }; +-#define __xg(x) ((volatile struct __xchg_dummy *)(x)) +- +-static inline unsigned long __xchg(unsigned long x, volatile void *ptr, +- int size) +-{ +- unsigned long tmp, flags; +- +- local_irq_save(flags); +- +- switch (size) { +- case 1: +- __asm__ __volatile__( +- "ldb %0, %2\n" +- "stb %1, %2\n" +- : "=&r" (tmp) +- : "r" (x), "m" (*__xg(ptr)) +- : "memory"); +- break; +- case 2: +- __asm__ __volatile__( +- "ldh %0, %2\n" +- "sth %1, %2\n" +- : "=&r" (tmp) +- : "r" (x), "m" (*__xg(ptr)) +- : "memory"); +- break; +- case 4: +- __asm__ __volatile__( +- "ldw %0, %2\n" +- "stw %1, %2\n" +- : "=&r" (tmp) +- : "r" (x), "m" (*__xg(ptr)) +- : "memory"); +- break; +- } +- +- local_irq_restore(flags); +- return tmp; +-} +- + #include <asm-generic/cmpxchg.h> +-#include <asm-generic/cmpxchg-local.h> + + #endif /* _ASM_NIOS2_CMPXCHG_H */ +-- +2.6.2 + diff --git a/patches.misc/input-add-support-for-rohm-bu21023-24-touchscreen.patch b/patches.misc/input-add-support-for-rohm-bu21023-24-touchscreen.patch new file mode 100644 index 00000000000000..2dfc9c31413706 --- /dev/null +++ b/patches.misc/input-add-support-for-rohm-bu21023-24-touchscreen.patch @@ -0,0 +1,1254 @@ +From c7efd123500b11568ce928a5cd91ad132ec36df5 Mon Sep 17 00:00:00 2001 +From: Yoichi Yuasa <yuasa@linux-mips.org> +Date: Sat, 19 Sep 2015 11:34:30 -0700 +Subject: [PATCH] Input: add support for ROHM BU21023/24 touchscreen + +This adds support for ROHM BU21023/24 Dual touch resistive touchscreens. + +Signed-off-by: Yoichi Yuasa <yuasa@linux-mips.org> +Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> + +--- + drivers/input/touchscreen/Kconfig | 11 + drivers/input/touchscreen/rohm_bu21023.c | 1218 +++++++++++++++++++++++++++++++ + 2 files changed, 1229 insertions(+) + +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -1027,4 +1027,15 @@ config TOUCHSCREEN_ZFORCE + To compile this driver as a module, choose M here: the + module will be called zforce_ts. + ++config TOUCHSCREEN_ROHM_BU21023 ++ tristate "ROHM BU21023/24 Dual touch support resistive touchscreens" ++ depends on I2C ++ help ++ Say Y here if you have a touchscreen using ROHM BU21023/24. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called bu21023_ts. ++ + endif +--- /dev/null ++++ b/drivers/input/touchscreen/rohm_bu21023.c +@@ -0,0 +1,1218 @@ ++/* ++ * ROHM BU21023/24 Dual touch support resistive touch screen driver ++ * Copyright (C) 2012 ROHM CO.,LTD. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#include <linux/delay.h> ++#include <linux/firmware.h> ++#include <linux/i2c.h> ++#include <linux/input.h> ++#include <linux/input/mt.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++ ++#define BU21023_NAME "bu21023_ts" ++#define BU21023_FIRMWARE_NAME "bu21023.bin" ++ ++#define MAX_CONTACTS 2 ++ ++#define AXIS_ADJUST 4 ++#define AXIS_OFFSET 8 ++ ++#define FIRMWARE_BLOCK_SIZE 32U ++#define FIRMWARE_RETRY_MAX 4 ++ ++#define SAMPLING_DELAY 12 /* msec */ ++ ++#define CALIBRATION_RETRY_MAX 6 ++ ++#define ROHM_TS_ABS_X_MIN 40 ++#define ROHM_TS_ABS_X_MAX 990 ++#define ROHM_TS_ABS_Y_MIN 160 ++#define ROHM_TS_ABS_Y_MAX 920 ++#define ROHM_TS_DISPLACEMENT_MAX 0 /* zero for infinite */ ++ ++/* ++ * BU21023GUL/BU21023MUV/BU21024FV-M registers map ++ */ ++#define VADOUT_YP_H 0x00 ++#define VADOUT_YP_L 0x01 ++#define VADOUT_XP_H 0x02 ++#define VADOUT_XP_L 0x03 ++#define VADOUT_YN_H 0x04 ++#define VADOUT_YN_L 0x05 ++#define VADOUT_XN_H 0x06 ++#define VADOUT_XN_L 0x07 ++ ++#define PRM1_X_H 0x08 ++#define PRM1_X_L 0x09 ++#define PRM1_Y_H 0x0a ++#define PRM1_Y_L 0x0b ++#define PRM2_X_H 0x0c ++#define PRM2_X_L 0x0d ++#define PRM2_Y_H 0x0e ++#define PRM2_Y_L 0x0f ++ ++#define MLT_PRM_MONI_X 0x10 ++#define MLT_PRM_MONI_Y 0x11 ++ ++#define DEBUG_MONI_1 0x12 ++#define DEBUG_MONI_2 0x13 ++ ++#define VADOUT_ZX_H 0x14 ++#define VADOUT_ZX_L 0x15 ++#define VADOUT_ZY_H 0x16 ++#define VADOUT_ZY_L 0x17 ++ ++#define Z_PARAM_H 0x18 ++#define Z_PARAM_L 0x19 ++ ++/* ++ * Value for VADOUT_*_L ++ */ ++#define VADOUT_L_MASK 0x01 ++ ++/* ++ * Value for PRM*_*_L ++ */ ++#define PRM_L_MASK 0x01 ++ ++#define POS_X1_H 0x20 ++#define POS_X1_L 0x21 ++#define POS_Y1_H 0x22 ++#define POS_Y1_L 0x23 ++#define POS_X2_H 0x24 ++#define POS_X2_L 0x25 ++#define POS_Y2_H 0x26 ++#define POS_Y2_L 0x27 ++ ++/* ++ * Value for POS_*_L ++ */ ++#define POS_L_MASK 0x01 ++ ++#define TOUCH 0x28 ++#define TOUCH_DETECT 0x01 ++ ++#define TOUCH_GESTURE 0x29 ++#define SINGLE_TOUCH 0x01 ++#define DUAL_TOUCH 0x03 ++#define TOUCH_MASK 0x03 ++#define CALIBRATION_REQUEST 0x04 ++#define CALIBRATION_STATUS 0x08 ++#define CALIBRATION_MASK 0x0c ++#define GESTURE_SPREAD 0x10 ++#define GESTURE_PINCH 0x20 ++#define GESTURE_ROTATE_R 0x40 ++#define GESTURE_ROTATE_L 0x80 ++ ++#define INT_STATUS 0x2a ++#define INT_MASK 0x3d ++#define INT_CLEAR 0x3e ++ ++/* ++ * Values for INT_* ++ */ ++#define COORD_UPDATE 0x01 ++#define CALIBRATION_DONE 0x02 ++#define SLEEP_IN 0x04 ++#define SLEEP_OUT 0x08 ++#define PROGRAM_LOAD_DONE 0x10 ++#define ERROR 0x80 ++#define INT_ALL 0x9f ++ ++#define ERR_STATUS 0x2b ++#define ERR_MASK 0x3f ++ ++/* ++ * Values for ERR_* ++ */ ++#define ADC_TIMEOUT 0x01 ++#define CPU_TIMEOUT 0x02 ++#define CALIBRATION_ERR 0x04 ++#define PROGRAM_LOAD_ERR 0x10 ++ ++#define COMMON_SETUP1 0x30 ++#define PROGRAM_LOAD_HOST 0x02 ++#define PROGRAM_LOAD_EEPROM 0x03 ++#define CENSOR_4PORT 0x04 ++#define CENSOR_8PORT 0x00 /* Not supported by BU21023 */ ++#define CALIBRATION_TYPE_DEFAULT 0x08 ++#define CALIBRATION_TYPE_SPECIAL 0x00 ++#define INT_ACTIVE_HIGH 0x10 ++#define INT_ACTIVE_LOW 0x00 ++#define AUTO_CALIBRATION 0x40 ++#define MANUAL_CALIBRATION 0x00 ++#define COMMON_SETUP1_DEFAULT 0x4e ++ ++#define COMMON_SETUP2 0x31 ++#define MAF_NONE 0x00 ++#define MAF_1SAMPLE 0x01 ++#define MAF_3SAMPLES 0x02 ++#define MAF_5SAMPLES 0x03 ++#define INV_Y 0x04 ++#define INV_X 0x08 ++#define SWAP_XY 0x10 ++ ++#define COMMON_SETUP3 0x32 ++#define EN_SLEEP 0x01 ++#define EN_MULTI 0x02 ++#define EN_GESTURE 0x04 ++#define EN_INTVL 0x08 ++#define SEL_STEP 0x10 ++#define SEL_MULTI 0x20 ++#define SEL_TBL_DEFAULT 0x40 ++ ++#define INTERVAL_TIME 0x33 ++#define INTERVAL_TIME_DEFAULT 0x10 ++ ++#define STEP_X 0x34 ++#define STEP_X_DEFAULT 0x41 ++ ++#define STEP_Y 0x35 ++#define STEP_Y_DEFAULT 0x8d ++ ++#define OFFSET_X 0x38 ++#define OFFSET_X_DEFAULT 0x0c ++ ++#define OFFSET_Y 0x39 ++#define OFFSET_Y_DEFAULT 0x0c ++ ++#define THRESHOLD_TOUCH 0x3a ++#define THRESHOLD_TOUCH_DEFAULT 0xa0 ++ ++#define THRESHOLD_GESTURE 0x3b ++#define THRESHOLD_GESTURE_DEFAULT 0x17 ++ ++#define SYSTEM 0x40 ++#define ANALOG_POWER_ON 0x01 ++#define ANALOG_POWER_OFF 0x00 ++#define CPU_POWER_ON 0x02 ++#define CPU_POWER_OFF 0x00 ++ ++#define FORCE_CALIBRATION 0x42 ++#define FORCE_CALIBRATION_ON 0x01 ++#define FORCE_CALIBRATION_OFF 0x00 ++ ++#define CPU_FREQ 0x50 /* 10 / (reg + 1) MHz */ ++#define CPU_FREQ_10MHZ 0x00 ++#define CPU_FREQ_5MHZ 0x01 ++#define CPU_FREQ_1MHZ 0x09 ++ ++#define EEPROM_ADDR 0x51 ++ ++#define CALIBRATION_ADJUST 0x52 ++#define CALIBRATION_ADJUST_DEFAULT 0x00 ++ ++#define THRESHOLD_SLEEP_IN 0x53 ++ ++#define EVR_XY 0x56 ++#define EVR_XY_DEFAULT 0x10 ++ ++#define PRM_SWOFF_TIME 0x57 ++#define PRM_SWOFF_TIME_DEFAULT 0x04 ++ ++#define PROGRAM_VERSION 0x5f ++ ++#define ADC_CTRL 0x60 ++#define ADC_DIV_MASK 0x1f /* The minimum value is 4 */ ++#define ADC_DIV_DEFAULT 0x08 ++ ++#define ADC_WAIT 0x61 ++#define ADC_WAIT_DEFAULT 0x0a ++ ++#define SWCONT 0x62 ++#define SWCONT_DEFAULT 0x0f ++ ++#define EVR_X 0x63 ++#define EVR_X_DEFAULT 0x86 ++ ++#define EVR_Y 0x64 ++#define EVR_Y_DEFAULT 0x64 ++ ++#define TEST1 0x65 ++#define DUALTOUCH_STABILIZE_ON 0x01 ++#define DUALTOUCH_STABILIZE_OFF 0x00 ++#define DUALTOUCH_REG_ON 0x20 ++#define DUALTOUCH_REG_OFF 0x00 ++ ++#define CALIBRATION_REG1 0x68 ++#define CALIBRATION_REG1_DEFAULT 0xd9 ++ ++#define CALIBRATION_REG2 0x69 ++#define CALIBRATION_REG2_DEFAULT 0x36 ++ ++#define CALIBRATION_REG3 0x6a ++#define CALIBRATION_REG3_DEFAULT 0x32 ++ ++#define EX_ADDR_H 0x70 ++#define EX_ADDR_L 0x71 ++#define EX_WDAT 0x72 ++#define EX_RDAT 0x73 ++#define EX_CHK_SUM1 0x74 ++#define EX_CHK_SUM2 0x75 ++#define EX_CHK_SUM3 0x76 ++ ++struct rohm_ts_data { ++ struct i2c_client *client; ++ struct input_dev *input; ++ ++ bool initialized; ++ ++ unsigned int contact_count[MAX_CONTACTS + 1]; ++ int finger_count; ++ ++ u8 setup2; ++}; ++ ++/* ++ * rohm_i2c_burst_read - execute combined I2C message for ROHM BU21023/24 ++ * @client: Handle to ROHM BU21023/24 ++ * @start: Where to start read address from ROHM BU21023/24 ++ * @buf: Where to store read data from ROHM BU21023/24 ++ * @len: How many bytes to read ++ * ++ * Returns negative errno, else zero on success. ++ * ++ * Note ++ * In BU21023/24 burst read, stop condition is needed after "address write". ++ * Therefore, transmission is performed in 2 steps. ++ */ ++static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf, ++ size_t len) ++{ ++ struct i2c_adapter *adap = client->adapter; ++ struct i2c_msg msg[2]; ++ int i, ret = 0; ++ ++ msg[0].addr = client->addr; ++ msg[0].flags = 0; ++ msg[0].len = 1; ++ msg[0].buf = &start; ++ ++ msg[1].addr = client->addr; ++ msg[1].flags = I2C_M_RD; ++ msg[1].len = len; ++ msg[1].buf = buf; ++ ++ i2c_lock_adapter(adap); ++ ++ for (i = 0; i < 2; i++) { ++ if (__i2c_transfer(adap, &msg[i], 1) < 0) { ++ ret = -EIO; ++ break; ++ } ++ } ++ ++ i2c_unlock_adapter(adap); ++ ++ return ret; ++} ++ ++static int rohm_ts_manual_calibration(struct rohm_ts_data *ts) ++{ ++ struct i2c_client *client = ts->client; ++ struct device *dev = &client->dev; ++ u8 buf[33]; /* for PRM1_X_H(0x08)-TOUCH(0x28) */ ++ ++ int retry; ++ bool success = false; ++ bool first_time = true; ++ bool calibration_done; ++ ++ u8 reg1, reg2, reg3; ++ s32 reg1_orig, reg2_orig, reg3_orig; ++ s32 val; ++ ++ int calib_x = 0, calib_y = 0; ++ int reg_x, reg_y; ++ int err_x, err_y; ++ ++ int error, error2; ++ int i; ++ ++ reg1_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG1); ++ if (reg1_orig < 0) ++ return reg1_orig; ++ ++ reg2_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG2); ++ if (reg2_orig < 0) ++ return reg2_orig; ++ ++ reg3_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG3); ++ if (reg3_orig < 0) ++ return reg3_orig; ++ ++ error = i2c_smbus_write_byte_data(client, INT_MASK, ++ COORD_UPDATE | SLEEP_IN | SLEEP_OUT | ++ PROGRAM_LOAD_DONE); ++ if (error) ++ goto out; ++ ++ error = i2c_smbus_write_byte_data(client, TEST1, ++ DUALTOUCH_STABILIZE_ON); ++ if (error) ++ goto out; ++ ++ for (retry = 0; retry < CALIBRATION_RETRY_MAX; retry++) { ++ /* wait 2 sampling for update */ ++ mdelay(2 * SAMPLING_DELAY); ++ ++#define READ_CALIB_BUF(reg) buf[((reg) - PRM1_X_H)] ++ ++ error = rohm_i2c_burst_read(client, PRM1_X_H, buf, sizeof(buf)); ++ if (error) ++ goto out; ++ ++ if (READ_CALIB_BUF(TOUCH) & TOUCH_DETECT) ++ continue; ++ ++ if (first_time) { ++ /* generate calibration parameter */ ++ calib_x = ((int)READ_CALIB_BUF(PRM1_X_H) << 2 | ++ READ_CALIB_BUF(PRM1_X_L)) - AXIS_OFFSET; ++ calib_y = ((int)READ_CALIB_BUF(PRM1_Y_H) << 2 | ++ READ_CALIB_BUF(PRM1_Y_L)) - AXIS_OFFSET; ++ ++ error = i2c_smbus_write_byte_data(client, TEST1, ++ DUALTOUCH_STABILIZE_ON | DUALTOUCH_REG_ON); ++ if (error) ++ goto out; ++ ++ first_time = false; ++ } else { ++ /* generate adjustment parameter */ ++ err_x = (int)READ_CALIB_BUF(PRM1_X_H) << 2 | ++ READ_CALIB_BUF(PRM1_X_L); ++ err_y = (int)READ_CALIB_BUF(PRM1_Y_H) << 2 | ++ READ_CALIB_BUF(PRM1_Y_L); ++ ++ /* X axis ajust */ ++ if (err_x <= 4) ++ calib_x -= AXIS_ADJUST; ++ else if (err_x >= 60) ++ calib_x += AXIS_ADJUST; ++ ++ /* Y axis ajust */ ++ if (err_y <= 4) ++ calib_y -= AXIS_ADJUST; ++ else if (err_y >= 60) ++ calib_y += AXIS_ADJUST; ++ } ++ ++ /* generate calibration setting value */ ++ reg_x = calib_x + ((calib_x & 0x200) << 1); ++ reg_y = calib_y + ((calib_y & 0x200) << 1); ++ ++ /* convert for register format */ ++ reg1 = reg_x >> 3; ++ reg2 = (reg_y & 0x7) << 4 | (reg_x & 0x7); ++ reg3 = reg_y >> 3; ++ ++ error = i2c_smbus_write_byte_data(client, ++ CALIBRATION_REG1, reg1); ++ if (error) ++ goto out; ++ ++ error = i2c_smbus_write_byte_data(client, ++ CALIBRATION_REG2, reg2); ++ if (error) ++ goto out; ++ ++ error = i2c_smbus_write_byte_data(client, ++ CALIBRATION_REG3, reg3); ++ if (error) ++ goto out; ++ ++ /* ++ * force calibration sequcence ++ */ ++ error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION, ++ FORCE_CALIBRATION_OFF); ++ if (error) ++ goto out; ++ ++ error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION, ++ FORCE_CALIBRATION_ON); ++ if (error) ++ goto out; ++ ++ /* clear all interrupts */ ++ error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); ++ if (error) ++ goto out; ++ ++ /* ++ * Wait for the status change of calibration, max 10 sampling ++ */ ++ calibration_done = false; ++ ++ for (i = 0; i < 10; i++) { ++ mdelay(SAMPLING_DELAY); ++ ++ val = i2c_smbus_read_byte_data(client, TOUCH_GESTURE); ++ if (!(val & CALIBRATION_MASK)) { ++ calibration_done = true; ++ break; ++ } else if (val < 0) { ++ error = val; ++ goto out; ++ } ++ } ++ ++ if (calibration_done) { ++ val = i2c_smbus_read_byte_data(client, INT_STATUS); ++ if (val == CALIBRATION_DONE) { ++ success = true; ++ break; ++ } else if (val < 0) { ++ error = val; ++ goto out; ++ } ++ } else { ++ dev_warn(dev, "calibration timeout\n"); ++ } ++ } ++ ++ if (!success) { ++ error = i2c_smbus_write_byte_data(client, CALIBRATION_REG1, ++ reg1_orig); ++ if (error) ++ goto out; ++ ++ error = i2c_smbus_write_byte_data(client, CALIBRATION_REG2, ++ reg2_orig); ++ if (error) ++ goto out; ++ ++ error = i2c_smbus_write_byte_data(client, CALIBRATION_REG3, ++ reg3_orig); ++ if (error) ++ goto out; ++ ++ /* calibration data enable */ ++ error = i2c_smbus_write_byte_data(client, TEST1, ++ DUALTOUCH_STABILIZE_ON | ++ DUALTOUCH_REG_ON); ++ if (error) ++ goto out; ++ ++ /* wait 10 sampling */ ++ mdelay(10 * SAMPLING_DELAY); ++ ++ error = -EBUSY; ++ } ++ ++out: ++ error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL); ++ if (!error2) ++ /* Clear all interrupts */ ++ error2 = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); ++ ++ return error ? error : error2; ++} ++ ++static const unsigned int untouch_threshold[3] = { 0, 1, 5 }; ++static const unsigned int single_touch_threshold[3] = { 0, 0, 4 }; ++static const unsigned int dual_touch_threshold[3] = { 10, 8, 0 }; ++ ++static irqreturn_t rohm_ts_soft_irq(int irq, void *dev_id) ++{ ++ struct rohm_ts_data *ts = dev_id; ++ struct i2c_client *client = ts->client; ++ struct input_dev *input_dev = ts->input; ++ struct device *dev = &client->dev; ++ ++ u8 buf[10]; /* for POS_X1_H(0x20)-TOUCH_GESTURE(0x29) */ ++ ++ struct input_mt_pos pos[MAX_CONTACTS]; ++ int slots[MAX_CONTACTS]; ++ u8 touch_flags; ++ unsigned int threshold; ++ int finger_count = -1; ++ int prev_finger_count = ts->finger_count; ++ int count; ++ int error; ++ int i; ++ ++ error = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL); ++ if (error) ++ return IRQ_HANDLED; ++ ++ /* Clear all interrupts */ ++ error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); ++ if (error) ++ return IRQ_HANDLED; ++ ++#define READ_POS_BUF(reg) buf[((reg) - POS_X1_H)] ++ ++ error = rohm_i2c_burst_read(client, POS_X1_H, buf, sizeof(buf)); ++ if (error) ++ return IRQ_HANDLED; ++ ++ touch_flags = READ_POS_BUF(TOUCH_GESTURE) & TOUCH_MASK; ++ if (touch_flags) { ++ /* generate coordinates */ ++ pos[0].x = ((s16)READ_POS_BUF(POS_X1_H) << 2) | ++ READ_POS_BUF(POS_X1_L); ++ pos[0].y = ((s16)READ_POS_BUF(POS_Y1_H) << 2) | ++ READ_POS_BUF(POS_Y1_L); ++ pos[1].x = ((s16)READ_POS_BUF(POS_X2_H) << 2) | ++ READ_POS_BUF(POS_X2_L); ++ pos[1].y = ((s16)READ_POS_BUF(POS_Y2_H) << 2) | ++ READ_POS_BUF(POS_Y2_L); ++ } ++ ++ switch (touch_flags) { ++ case 0: ++ threshold = untouch_threshold[prev_finger_count]; ++ if (++ts->contact_count[0] >= threshold) ++ finger_count = 0; ++ break; ++ ++ case SINGLE_TOUCH: ++ threshold = single_touch_threshold[prev_finger_count]; ++ if (++ts->contact_count[1] >= threshold) ++ finger_count = 1; ++ ++ if (finger_count == 1) { ++ if (pos[1].x != 0 && pos[1].y != 0) { ++ pos[0].x = pos[1].x; ++ pos[0].y = pos[1].y; ++ pos[1].x = 0; ++ pos[1].y = 0; ++ } ++ } ++ break; ++ ++ case DUAL_TOUCH: ++ threshold = dual_touch_threshold[prev_finger_count]; ++ if (++ts->contact_count[2] >= threshold) ++ finger_count = 2; ++ break; ++ ++ default: ++ dev_dbg(dev, ++ "Three or more touches are not supported\n"); ++ return IRQ_HANDLED; ++ } ++ ++ if (finger_count >= 0) { ++ if (prev_finger_count != finger_count) { ++ count = ts->contact_count[finger_count]; ++ memset(ts->contact_count, 0, sizeof(ts->contact_count)); ++ ts->contact_count[finger_count] = count; ++ } ++ ++ input_mt_assign_slots(input_dev, slots, pos, ++ finger_count, ROHM_TS_DISPLACEMENT_MAX); ++ ++ for (i = 0; i < finger_count; i++) { ++ input_mt_slot(input_dev, slots[i]); ++ input_mt_report_slot_state(input_dev, ++ MT_TOOL_FINGER, true); ++ input_report_abs(input_dev, ++ ABS_MT_POSITION_X, pos[i].x); ++ input_report_abs(input_dev, ++ ABS_MT_POSITION_Y, pos[i].y); ++ } ++ ++ input_mt_sync_frame(input_dev); ++ input_mt_report_pointer_emulation(input_dev, true); ++ input_sync(input_dev); ++ ++ ts->finger_count = finger_count; ++ } ++ ++ if (READ_POS_BUF(TOUCH_GESTURE) & CALIBRATION_REQUEST) { ++ error = rohm_ts_manual_calibration(ts); ++ if (error) ++ dev_warn(dev, "manual calibration failed: %d\n", ++ error); ++ } ++ ++ i2c_smbus_write_byte_data(client, INT_MASK, ++ CALIBRATION_DONE | SLEEP_OUT | SLEEP_IN | ++ PROGRAM_LOAD_DONE); ++ ++ return IRQ_HANDLED; ++} ++ ++static int rohm_ts_load_firmware(struct i2c_client *client, ++ const char *firmware_name) ++{ ++ struct device *dev = &client->dev; ++ const struct firmware *fw; ++ s32 status; ++ unsigned int offset, len, xfer_len; ++ unsigned int retry = 0; ++ int error, error2; ++ ++ error = request_firmware(&fw, firmware_name, dev); ++ if (error) { ++ dev_err(dev, "unable to retrieve firmware %s: %d\n", ++ firmware_name, error); ++ return error; ++ } ++ ++ error = i2c_smbus_write_byte_data(client, INT_MASK, ++ COORD_UPDATE | CALIBRATION_DONE | ++ SLEEP_IN | SLEEP_OUT); ++ if (error) ++ goto out; ++ ++ do { ++ if (retry) { ++ dev_warn(dev, "retrying firmware load\n"); ++ ++ /* settings for retry */ ++ error = i2c_smbus_write_byte_data(client, EX_WDAT, 0); ++ if (error) ++ goto out; ++ } ++ ++ error = i2c_smbus_write_byte_data(client, EX_ADDR_H, 0); ++ if (error) ++ goto out; ++ ++ error = i2c_smbus_write_byte_data(client, EX_ADDR_L, 0); ++ if (error) ++ goto out; ++ ++ error = i2c_smbus_write_byte_data(client, COMMON_SETUP1, ++ COMMON_SETUP1_DEFAULT); ++ if (error) ++ goto out; ++ ++ /* firmware load to the device */ ++ offset = 0; ++ len = fw->size; ++ ++ while (len) { ++ xfer_len = min(FIRMWARE_BLOCK_SIZE, len); ++ ++ error = i2c_smbus_write_i2c_block_data(client, EX_WDAT, ++ xfer_len, &fw->data[offset]); ++ if (error) ++ goto out; ++ ++ len -= xfer_len; ++ offset += xfer_len; ++ } ++ ++ /* check firmware load result */ ++ status = i2c_smbus_read_byte_data(client, INT_STATUS); ++ if (status < 0) { ++ error = status; ++ goto out; ++ } ++ ++ /* clear all interrupts */ ++ error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); ++ if (error) ++ goto out; ++ ++ if (status == PROGRAM_LOAD_DONE) ++ break; ++ ++ error = -EIO; ++ } while (++retry >= FIRMWARE_RETRY_MAX); ++ ++out: ++ error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL); ++ ++ release_firmware(fw); ++ ++ return error ? error : error2; ++} ++ ++static ssize_t swap_xy_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct rohm_ts_data *ts = i2c_get_clientdata(client); ++ ++ return sprintf(buf, "%d\n", !!(ts->setup2 & SWAP_XY)); ++} ++ ++static ssize_t swap_xy_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct rohm_ts_data *ts = i2c_get_clientdata(client); ++ unsigned int val; ++ int error; ++ ++ error = kstrtouint(buf, 0, &val); ++ if (error) ++ return error; ++ ++ error = mutex_lock_interruptible(&ts->input->mutex); ++ if (error) ++ return error; ++ ++ if (val) ++ ts->setup2 |= SWAP_XY; ++ else ++ ts->setup2 &= ~SWAP_XY; ++ ++ if (ts->initialized) ++ error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2, ++ ts->setup2); ++ ++ mutex_unlock(&ts->input->mutex); ++ ++ return error ? error : count; ++} ++ ++static ssize_t inv_x_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct rohm_ts_data *ts = i2c_get_clientdata(client); ++ ++ return sprintf(buf, "%d\n", !!(ts->setup2 & INV_X)); ++} ++ ++static ssize_t inv_x_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct rohm_ts_data *ts = i2c_get_clientdata(client); ++ unsigned int val; ++ int error; ++ ++ error = kstrtouint(buf, 0, &val); ++ if (error) ++ return error; ++ ++ error = mutex_lock_interruptible(&ts->input->mutex); ++ if (error) ++ return error; ++ ++ if (val) ++ ts->setup2 |= INV_X; ++ else ++ ts->setup2 &= ~INV_X; ++ ++ if (ts->initialized) ++ error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2, ++ ts->setup2); ++ ++ mutex_unlock(&ts->input->mutex); ++ ++ return error ? error : count; ++} ++ ++static ssize_t inv_y_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct rohm_ts_data *ts = i2c_get_clientdata(client); ++ ++ return sprintf(buf, "%d\n", !!(ts->setup2 & INV_Y)); ++} ++ ++static ssize_t inv_y_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct rohm_ts_data *ts = i2c_get_clientdata(client); ++ unsigned int val; ++ int error; ++ ++ error = kstrtouint(buf, 0, &val); ++ if (error) ++ return error; ++ ++ error = mutex_lock_interruptible(&ts->input->mutex); ++ if (error) ++ return error; ++ ++ if (val) ++ ts->setup2 |= INV_Y; ++ else ++ ts->setup2 &= ~INV_Y; ++ ++ if (ts->initialized) ++ error = i2c_smbus_write_byte_data(client, COMMON_SETUP2, ++ ts->setup2); ++ ++ mutex_unlock(&ts->input->mutex); ++ ++ return error ? error : count; ++} ++ ++static DEVICE_ATTR_RW(swap_xy); ++static DEVICE_ATTR_RW(inv_x); ++static DEVICE_ATTR_RW(inv_y); ++ ++static struct attribute *rohm_ts_attrs[] = { ++ &dev_attr_swap_xy.attr, ++ &dev_attr_inv_x.attr, ++ &dev_attr_inv_y.attr, ++ NULL, ++}; ++ ++static const struct attribute_group rohm_ts_attr_group = { ++ .attrs = rohm_ts_attrs, ++}; ++ ++static int rohm_ts_device_init(struct i2c_client *client, u8 setup2) ++{ ++ struct device *dev = &client->dev; ++ int error; ++ ++ disable_irq(client->irq); ++ ++ /* ++ * Wait 200usec for reset ++ */ ++ udelay(200); ++ ++ /* Release analog reset */ ++ error = i2c_smbus_write_byte_data(client, SYSTEM, ++ ANALOG_POWER_ON | CPU_POWER_OFF); ++ if (error) ++ return error; ++ ++ /* Waiting for the analog warm-up, max. 200usec */ ++ udelay(200); ++ ++ /* clear all interrupts */ ++ error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, EX_WDAT, 0); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, COMMON_SETUP1, 0); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, COMMON_SETUP2, setup2); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, COMMON_SETUP3, ++ SEL_TBL_DEFAULT | EN_MULTI); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, THRESHOLD_GESTURE, ++ THRESHOLD_GESTURE_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, INTERVAL_TIME, ++ INTERVAL_TIME_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, CPU_FREQ, CPU_FREQ_10MHZ); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, PRM_SWOFF_TIME, ++ PRM_SWOFF_TIME_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, ADC_CTRL, ADC_DIV_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, ADC_WAIT, ADC_WAIT_DEFAULT); ++ if (error) ++ return error; ++ ++ /* ++ * Panel setup, these values change with the panel. ++ */ ++ error = i2c_smbus_write_byte_data(client, STEP_X, STEP_X_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, STEP_Y, STEP_Y_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, OFFSET_X, OFFSET_X_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, OFFSET_Y, OFFSET_Y_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, THRESHOLD_TOUCH, ++ THRESHOLD_TOUCH_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, EVR_XY, EVR_XY_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, EVR_X, EVR_X_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, EVR_Y, EVR_Y_DEFAULT); ++ if (error) ++ return error; ++ ++ /* Fixed value settings */ ++ error = i2c_smbus_write_byte_data(client, CALIBRATION_ADJUST, ++ CALIBRATION_ADJUST_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, SWCONT, SWCONT_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, TEST1, ++ DUALTOUCH_STABILIZE_ON | ++ DUALTOUCH_REG_ON); ++ if (error) ++ return error; ++ ++ error = rohm_ts_load_firmware(client, BU21023_FIRMWARE_NAME); ++ if (error) { ++ dev_err(dev, "failed to load firmware: %d\n", error); ++ return error; ++ } ++ ++ /* ++ * Manual calibration results are not changed in same environment. ++ * If the force calibration is performed, ++ * the controller will not require calibration request interrupt ++ * when the typical values are set to the calibration registers. ++ */ ++ error = i2c_smbus_write_byte_data(client, CALIBRATION_REG1, ++ CALIBRATION_REG1_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, CALIBRATION_REG2, ++ CALIBRATION_REG2_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, CALIBRATION_REG3, ++ CALIBRATION_REG3_DEFAULT); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION, ++ FORCE_CALIBRATION_OFF); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION, ++ FORCE_CALIBRATION_ON); ++ if (error) ++ return error; ++ ++ /* Clear all interrupts */ ++ error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); ++ if (error) ++ return error; ++ ++ /* Enable coordinates update interrupt */ ++ error = i2c_smbus_write_byte_data(client, INT_MASK, ++ CALIBRATION_DONE | SLEEP_OUT | ++ SLEEP_IN | PROGRAM_LOAD_DONE); ++ if (error) ++ return error; ++ ++ error = i2c_smbus_write_byte_data(client, ERR_MASK, ++ PROGRAM_LOAD_ERR | CPU_TIMEOUT | ++ ADC_TIMEOUT); ++ if (error) ++ return error; ++ ++ /* controller CPU power on */ ++ error = i2c_smbus_write_byte_data(client, SYSTEM, ++ ANALOG_POWER_ON | CPU_POWER_ON); ++ ++ enable_irq(client->irq); ++ ++ return error; ++} ++ ++static int rohm_ts_power_off(struct i2c_client *client) ++{ ++ int error; ++ ++ error = i2c_smbus_write_byte_data(client, SYSTEM, ++ ANALOG_POWER_ON | CPU_POWER_OFF); ++ if (error) { ++ dev_err(&client->dev, ++ "failed to power off device CPU: %d\n", error); ++ return error; ++ } ++ ++ error = i2c_smbus_write_byte_data(client, SYSTEM, ++ ANALOG_POWER_OFF | CPU_POWER_OFF); ++ if (error) ++ dev_err(&client->dev, ++ "failed to power off the device: %d\n", error); ++ ++ return error; ++} ++ ++static int rohm_ts_open(struct input_dev *input_dev) ++{ ++ struct rohm_ts_data *ts = input_get_drvdata(input_dev); ++ struct i2c_client *client = ts->client; ++ int error; ++ ++ if (!ts->initialized) { ++ error = rohm_ts_device_init(client, ts->setup2); ++ if (error) { ++ dev_err(&client->dev, ++ "device initialization failed: %d\n", error); ++ return error; ++ } ++ ++ ts->initialized = true; ++ } ++ ++ return 0; ++} ++ ++static void rohm_ts_close(struct input_dev *input_dev) ++{ ++ struct rohm_ts_data *ts = input_get_drvdata(input_dev); ++ ++ rohm_ts_power_off(ts->client); ++ ++ ts->initialized = false; ++} ++ ++static void rohm_ts_remove_sysfs_group(void *_dev) ++{ ++ struct device *dev = _dev; ++ ++ sysfs_remove_group(&dev->kobj, &rohm_ts_attr_group); ++} ++ ++static int rohm_bu21023_i2c_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ struct rohm_ts_data *ts; ++ struct input_dev *input; ++ int error; ++ ++ if (!client->irq) { ++ dev_err(dev, "IRQ is not assigned\n"); ++ return -EINVAL; ++ } ++ ++ if (!client->adapter->algo->master_xfer) { ++ dev_err(dev, "I2C level transfers not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ /* Turn off CPU just in case */ ++ error = rohm_ts_power_off(client); ++ if (error) ++ return error; ++ ++ ts = devm_kzalloc(dev, sizeof(struct rohm_ts_data), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ ++ ts->client = client; ++ ts->setup2 = MAF_1SAMPLE; ++ i2c_set_clientdata(client, ts); ++ ++ input = devm_input_allocate_device(dev); ++ if (!input) ++ return -ENOMEM; ++ ++ input->name = BU21023_NAME; ++ input->id.bustype = BUS_I2C; ++ input->open = rohm_ts_open; ++ input->close = rohm_ts_close; ++ ++ ts->input = input; ++ input_set_drvdata(input, ts); ++ ++ input_set_abs_params(input, ABS_MT_POSITION_X, ++ ROHM_TS_ABS_X_MIN, ROHM_TS_ABS_X_MAX, 0, 0); ++ input_set_abs_params(input, ABS_MT_POSITION_Y, ++ ROHM_TS_ABS_Y_MIN, ROHM_TS_ABS_Y_MAX, 0, 0); ++ ++ error = input_mt_init_slots(input, MAX_CONTACTS, ++ INPUT_MT_DIRECT | INPUT_MT_TRACK | ++ INPUT_MT_DROP_UNUSED); ++ if (error) { ++ dev_err(dev, "failed to multi touch slots initialization\n"); ++ return error; ++ } ++ ++ error = devm_request_threaded_irq(dev, client->irq, ++ NULL, rohm_ts_soft_irq, ++ IRQF_ONESHOT, client->name, ts); ++ if (error) { ++ dev_err(dev, "failed to request IRQ: %d\n", error); ++ return error; ++ } ++ ++ error = input_register_device(input); ++ if (error) { ++ dev_err(dev, "failed to register input device: %d\n", error); ++ return error; ++ } ++ ++ error = sysfs_create_group(&dev->kobj, &rohm_ts_attr_group); ++ if (error) { ++ dev_err(dev, "failed to create sysfs group: %d\n", error); ++ return error; ++ } ++ ++ error = devm_add_action(dev, rohm_ts_remove_sysfs_group, dev); ++ if (error) { ++ rohm_ts_remove_sysfs_group(dev); ++ dev_err(&client->dev, ++ "Failed to add sysfs cleanup action: %d\n", ++ error); ++ return error; ++ } ++ ++ return error; ++} ++ ++static const struct i2c_device_id rohm_bu21023_i2c_id[] = { ++ { BU21023_NAME, 0 }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id); ++ ++static struct i2c_driver rohm_bu21023_i2c_driver = { ++ .driver = { ++ .name = BU21023_NAME, ++ }, ++ .probe = rohm_bu21023_i2c_probe, ++ .id_table = rohm_bu21023_i2c_id, ++}; ++module_i2c_driver(rohm_bu21023_i2c_driver); ++ ++MODULE_DESCRIPTION("ROHM BU21023/24 Touchscreen driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("ROHM Co., Ltd."); @@ -18,15 +18,6 @@ patches.ltsi/ltsi-makefile-addition.patch ############################################################################# -# ktap -# -# 0.4 version of ktap, taken from the upstream: -# https://github.com/ktap/ktap.git -# repo. -# -#patches.ktap/ktap-0.4.patch - -############################################################################# # Renesas patches # patches.renesas/0001-ARM-shmobile-r8a73a4-Add-IRQC-clock-to-device-tree.patch @@ -413,13 +404,22 @@ patches.altera/0004-fpga-manager-add-driver-for-socfpga-fpga-manager.patch patches.altera/0005-MAINTAINERS-add-fpga-manager-framework.patch patches.altera/0006-ARM-socfpga_defconfig-enable-fpga-manager.patch patches.altera/0007-ARM-socfpga-dts-add-fpga-manager.patch - +patches.altera/0001-nios2-Export-get_cycles.patch +patches.altera/0002-nios2-check-number-of-timer-instances.patch +patches.altera/0003-nios2-time-Migrate-to-new-set-state-interface.patch +patches.altera/0004-nios2-fixed-variable-imm16-to-s16.patch +patches.altera/0005-nios2-remove-unused-statistic-counters.patch +patches.altera/0006-nios2-Add-Max10-device-tree.patch +patches.altera/0007-nios2-add-Max10-defconfig.patch +patches.altera/0008-nios2-Fix-unused-variable-warning.patch +patches.altera/0009-nios2-Switch-to-generic-__xchg.patch ############################################################################# -# fixes that go after all of the above -# - - +# Misc patches +patches.misc/input-add-support-for-rohm-bu21023-24-touchscreen.patch +############################################################################## +# fixes that go after all of the above +# |