/* * GPIO driver for NVIDIA Tegra186 * * Copyright (c) 2015-2020, NVIDIA CORPORATION. All rights reserved. * * Author: Suresh Mangipudi * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* GPIO control registers */ #define GPIO_ENB_CONFIG_REG 0x00 #define GPIO_DBC_THRES_REG 0x04 #define GPIO_INPUT_REG 0x08 #define GPIO_OUT_CTRL_REG 0x0c #define GPIO_OUT_VAL_REG 0x10 #define GPIO_INT_CLEAR_REG 0x14 #define GPIO_REG_DIFF 0x20 #define GPIO_INT_STATUS_OFFSET 0x100 #define ROUTE_MAP_OFFSET 0x14 #define GPIO_VM_REG 0x00 #define GPIO_VM_RW 0x03 /* GPIO SCR registers */ #define GPIO_SCR_REG 0x04 #define GPIO_SCR_DIFF 0x08 #define GPIO_SCR_BASE_DIFF 0x40 #define GPIO_ENB_BIT BIT(0) #define GPIO_INOUT_BIT BIT(1) #define GPIO_TRG_TYPE_BIT(x) ((x) & 0x3) #define GPIO_TRG_TYPE_BIT_OFFSET 0x2 #define GPIO_TRG_LVL_BIT BIT(4) #define GPIO_DEB_FUNC_BIT BIT(5) #define GPIO_INT_FUNC_BIT BIT(6) #define GPIO_TIMESTAMP_FUNC_BIT 0x7 #define GPIO_DBC_THRES_BIT(val) ((val) & 0xFF) #define GPIO_SCR_SEC_WEN BIT(28) #define GPIO_SCR_SEC_REN BIT(27) #define GPIO_SCR_SEC_G1W BIT(9) #define GPIO_SCR_SEC_G1R BIT(1) #define GPIO_FULL_ACCESS (GPIO_SCR_SEC_WEN | \ GPIO_SCR_SEC_REN | \ GPIO_SCR_SEC_G1R | \ GPIO_SCR_SEC_G1W) #define GPIO_SCR_SEC_ENABLE (GPIO_SCR_SEC_WEN | \ GPIO_SCR_SEC_REN) #define GPIO_INT_LVL_NO_TRIGGER 0x0 #define GPIO_INT_LVL_LEVEL_TRIGGER 0x1 #define GPIO_INT_LVL_SINGLE_EDGE_TRIGGER 0x2 #define GPIO_INT_LVL_BOTH_EDGE_TRIGGER 0x3 #define TRIGGER_LEVEL_LOW 0x0 #define TRIGGER_LEVEL_HIGH 0x1 #define GPIO_STATUS_G1 0x04 #define MAX_GPIO_CONTROLLERS 7 #define MAX_GPIO_PORTS 8 #define MAX_IRQS 8 #define MAX_GPIO_IRQS (MAX_GPIO_CONTROLLERS * MAX_GPIO_PORTS * 8) #define GPIO_PORT(g) ((g) >> 3) #define GPIO_PIN(g) ((g) & 0x7) #define GPIO_INTERRUPT_UNMASK_ENABLE 0x1 #define GPIO_PIN_DIRECTION_INPUT 0x2 /******************** GTE Registers ******************************/ #define GTE_GPIO_TECTRL 0x0 #define GTE_GPIO_TETSCH 0x4 #define GTE_GPIO_TETSCL 0x8 #define GTE_GPIO_TESRC 0xC #define GTE_GPIO_TECCV 0x10 #define GTE_GPIO_TEPCV 0x14 #define GTE_GPIO_TEENCV 0x18 #define GTE_GPIO_TECMD 0x1C #define GTE_GPIO_TESTATUS 0x20 #define GTE_GPIO_SLICE0_TETEN 0x40 #define GTE_GPIO_SLICE0_TETDIS 0x44 #define GTE_GPIO_SLICE1_TETEN 0x60 #define GTE_GPIO_SLICE1_TETDIS 0x64 #define GTE_GPIO_SLICE2_TETEN 0x80 #define GTE_GPIO_SLICE2_TETDIS 0x84 #define GTE_GPIO_TECTRL_ENABLE_SHIFT 0 #define GTE_GPIO_TECTRL_ENABLE_MASK 0x1 #define GTE_GPIO_TECTRL_ENABLE_DISABLE 0x0 #define GTE_GPIO_TECTRL_ENABLE_ENABLE 0x1 #define GTE_GPIO_TESRC_SLICE_SHIFT 16 #define GTE_GPIO_TESRC_SLICE_DEFAULT_MASK 0xFF #define GTE_GPIO_TECMD_CMD_POP 0x1 #define GTE_GPIO_TESTATUS_OCCUPANCY_SHIFT 8 #define GTE_GPIO_TESTATUS_OCCUPANCY_MASK 0xFF #define AON_GPIO_SLICE1_MAP 0x3000 #define AON_GPIO_SLICE2_MAP 0xFFFFFFF #define AON_GPIO_SLICE1_INDEX 1 #define AON_GPIO_SLICE2_INDEX 2 #define BASE_ADDRESS_GTE_GPIO_SLICE0 0x40 #define BASE_ADDRESS_GTE_GPIO_SLICE1 0x60 #define BASE_ADDRESS_GTE_GPIO_SLICE2 0x80 #define GTE_GPIO_SLICE_SIZE (BASE_ADDRESS_GTE_GPIO_SLICE1 - \ BASE_ADDRESS_GTE_GPIO_SLICE0) /* AON GPIOS are mapped to only slice 1 and slice 2 */ /* GTE Interrupt connections. For slice 1 */ #define NV_AON_GTE_SLICE1_IRQ_LIC0 0 #define NV_AON_GTE_SLICE1_IRQ_LIC1 1 #define NV_AON_GTE_SLICE1_IRQ_LIC2 2 #define NV_AON_GTE_SLICE1_IRQ_LIC3 3 #define NV_AON_GTE_SLICE1_IRQ_APBERR 4 #define NV_AON_GTE_SLICE1_IRQ_GPIO 5 #define NV_AON_GTE_SLICE1_IRQ_WAKE0 6 #define NV_AON_GTE_SLICE1_IRQ_PMC 7 #define NV_AON_GTE_SLICE1_IRQ_DMIC 8 #define NV_AON_GTE_SLICE1_IRQ_PM 9 #define NV_AON_GTE_SLICE1_IRQ_FPUINT 10 #define NV_AON_GTE_SLICE1_IRQ_AOVC 11 #define NV_AON_GTE_SLICE1_IRQ_GPIO_28 12 #define NV_AON_GTE_SLICE1_IRQ_GPIO_29 13 #define NV_AON_GTE_SLICE1_IRQ_GPIO_30 14 #define NV_AON_GTE_SLICE1_IRQ_GPIO_31 15 #define NV_AON_GTE_SLICE1_IRQ_GPIO_32 16 #define NV_AON_GTE_SLICE1_IRQ_GPIO_33 17 #define NV_AON_GTE_SLICE1_IRQ_GPIO_34 18 #define NV_AON_GTE_SLICE1_IRQ_GPIO_35 19 #define NV_AON_GTE_SLICE1_IRQ_GPIO_36 20 #define NV_AON_GTE_SLICE1_IRQ_GPIO_37 21 #define NV_AON_GTE_SLICE1_IRQ_GPIO_38 22 #define NV_AON_GTE_SLICE1_IRQ_GPIO_39 23 #define NV_AON_GTE_SLICE1_IRQ_GPIO_40 24 #define NV_AON_GTE_SLICE1_IRQ_GPIO_41 25 #define NV_AON_GTE_SLICE1_IRQ_GPIO_42 26 #define NV_AON_GTE_SLICE1_IRQ_GPIO_43 27 /* GTE Interrupt connections. For slice 2 */ #define NV_AON_GTE_SLICE2_IRQ_GPIO_0 0 #define NV_AON_GTE_SLICE2_IRQ_GPIO_1 1 #define NV_AON_GTE_SLICE2_IRQ_GPIO_2 2 #define NV_AON_GTE_SLICE2_IRQ_GPIO_3 3 #define NV_AON_GTE_SLICE2_IRQ_GPIO_4 4 #define NV_AON_GTE_SLICE2_IRQ_GPIO_5 5 #define NV_AON_GTE_SLICE2_IRQ_GPIO_6 6 #define NV_AON_GTE_SLICE2_IRQ_GPIO_7 7 #define NV_AON_GTE_SLICE2_IRQ_GPIO_8 8 #define NV_AON_GTE_SLICE2_IRQ_GPIO_9 9 #define NV_AON_GTE_SLICE2_IRQ_GPIO_10 10 #define NV_AON_GTE_SLICE2_IRQ_GPIO_11 11 #define NV_AON_GTE_SLICE2_IRQ_GPIO_12 12 #define NV_AON_GTE_SLICE2_IRQ_GPIO_13 13 #define NV_AON_GTE_SLICE2_IRQ_GPIO_14 14 #define NV_AON_GTE_SLICE2_IRQ_GPIO_15 15 #define NV_AON_GTE_SLICE2_IRQ_GPIO_16 16 #define NV_AON_GTE_SLICE2_IRQ_GPIO_17 17 #define NV_AON_GTE_SLICE2_IRQ_GPIO_18 18 #define NV_AON_GTE_SLICE2_IRQ_GPIO_19 19 #define NV_AON_GTE_SLICE2_IRQ_GPIO_20 20 #define NV_AON_GTE_SLICE2_IRQ_GPIO_21 21 #define NV_AON_GTE_SLICE2_IRQ_GPIO_22 22 #define NV_AON_GTE_SLICE2_IRQ_GPIO_23 23 #define NV_AON_GTE_SLICE2_IRQ_GPIO_24 24 #define NV_AON_GTE_SLICE2_IRQ_GPIO_25 25 #define NV_AON_GTE_SLICE2_IRQ_GPIO_26 26 #define NV_AON_GTE_SLICE2_IRQ_GPIO_27 27 /**************************************************************/ static const int tegra186_gpio_wakes[] = { TEGRA_MAIN_GPIO(A, 6), /* wake0 */ TEGRA_MAIN_GPIO(A, 2), /* wake1 */ TEGRA_MAIN_GPIO(A, 5), /* wake2 */ TEGRA_MAIN_GPIO(D, 3), /* wake3 */ TEGRA_MAIN_GPIO(E, 3), /* wake4 */ TEGRA_MAIN_GPIO(G, 3), /* wake5 */ -EINVAL, /* wake6 */ TEGRA_MAIN_GPIO(B, 3), /* wake7 */ TEGRA_MAIN_GPIO(B, 5), /* wake8 */ TEGRA_MAIN_GPIO(C, 0), /* wake9 */ -EINVAL, /* wake10 */ TEGRA_MAIN_GPIO(H, 2), /* wake11 */ TEGRA_MAIN_GPIO(J, 5), /* wake12 */ TEGRA_MAIN_GPIO(J, 6), /* wake13 */ TEGRA_MAIN_GPIO(J, 7), /* wake14 */ TEGRA_MAIN_GPIO(K, 0), /* wake15 */ TEGRA_MAIN_GPIO(Q, 1), /* wake16 */ TEGRA_MAIN_GPIO(F, 4), /* wake17 */ TEGRA_MAIN_GPIO(M, 5), /* wake18 */ TEGRA_MAIN_GPIO(P, 0), /* wake19 */ TEGRA_MAIN_GPIO(P, 2), /* wake20 */ TEGRA_MAIN_GPIO(P, 1), /* wake21 */ TEGRA_MAIN_GPIO(O, 3), /* wake22 */ TEGRA_MAIN_GPIO(R, 5), /* wake23 */ -EINVAL, /* wake24 */ -EINVAL, /* wake25 */ -EINVAL, /* wake26 */ -EINVAL, /* wake27 */ TEGRA_MAIN_GPIO(F, 2), /* wake28 */ -EINVAL, /* wake29 */ -EINVAL, /* wake30 */ TEGRA_MAIN_GPIO(C, 6), /* wake31 */ -EINVAL, /* wake32 */ -EINVAL, /* wake33 */ -EINVAL, /* wake34 */ -EINVAL, /* wake35 */ -EINVAL, /* wake36 */ -EINVAL, /* wake37 */ -EINVAL, /* wake38 */ -EINVAL, /* wake39 */ -EINVAL, /* wake40 */ -EINVAL, /* wake41 */ -EINVAL, /* wake42 */ -EINVAL, /* wake43 */ -EINVAL, /* wake44 */ -EINVAL, /* wake45 */ -EINVAL, /* wake46 */ -EINVAL, /* wake47 */ -EINVAL, /* wake48 */ -EINVAL, /* wake49 */ -EINVAL, /* wake50 */ -EINVAL, /* wake51 */ TEGRA_MAIN_GPIO(X, 3), /* wake52 */ TEGRA_MAIN_GPIO(X, 7), /* wake53 */ TEGRA_MAIN_GPIO(Y, 0), /* wake54 */ TEGRA_MAIN_GPIO(Y, 1), /* wake55 */ TEGRA_MAIN_GPIO(Y, 2), /* wake56 */ TEGRA_MAIN_GPIO(Y, 5), /* wake57 */ TEGRA_MAIN_GPIO(Y, 6), /* wake58 */ TEGRA_MAIN_GPIO(L, 1), /* wake59 */ TEGRA_MAIN_GPIO(L, 3), /* wake60 */ TEGRA_MAIN_GPIO(L, 4), /* wake61 */ TEGRA_MAIN_GPIO(L, 5), /* wake62 */ TEGRA_MAIN_GPIO(I, 4), /* wake63 */ TEGRA_MAIN_GPIO(I, 6), /* wake64 */ -EINVAL, /* wake65 */ -EINVAL, /* wake66 */ -EINVAL, /* wake67 */ -EINVAL, /* wake68 */ -EINVAL, /* wake69 */ TEGRA_MAIN_GPIO(H, 3), /* wake70 */ TEGRA_MAIN_GPIO(P, 5), /* wake71 */ -EINVAL, /* wake72 */ -EINVAL, /* wake73 */ -EINVAL, /* wake74 */ -EINVAL, /* wake75 */ -EINVAL, /* wake76 */ -EINVAL, /* wake77 */ -EINVAL, /* wake78 */ -EINVAL, /* wake79 */ -EINVAL, /* wake80 */ -EINVAL, /* wake81 */ -EINVAL, /* wake82 */ -EINVAL, /* wake83 */ -EINVAL, /* wake84 */ -EINVAL, /* wake85 */ -EINVAL, /* wake86 */ -EINVAL, /* wake87 */ -EINVAL, /* wake88 */ -EINVAL, /* wake89 */ -EINVAL, /* wake90 */ -EINVAL, /* wake91 */ -EINVAL, /* wake92 */ -EINVAL, /* wake93 */ -EINVAL, /* wake94 */ -EINVAL, /* wake95 */ }; static const int tegra186_aon_gpio_wakes[] = { -EINVAL, /* wake0 */ -EINVAL, /* wake1 */ -EINVAL, /* wake2 */ -EINVAL, /* wake3 */ -EINVAL, /* wake4 */ -EINVAL, /* wake5 */ -EINVAL, /* wake6 */ -EINVAL, /* wake7 */ -EINVAL, /* wake8 */ -EINVAL, /* wake9 */ TEGRA_AON_GPIO(S, 2), /* wake10 */ -EINVAL, /* wake11 */ -EINVAL, /* wake12 */ -EINVAL, /* wake13 */ -EINVAL, /* wake14 */ -EINVAL, /* wake15 */ -EINVAL, /* wake16 */ -EINVAL, /* wake17 */ -EINVAL, /* wake18 */ -EINVAL, /* wake19 */ -EINVAL, /* wake20 */ -EINVAL, /* wake21 */ -EINVAL, /* wake22 */ -EINVAL, /* wake23 */ -EINVAL, /* wake24 */ TEGRA_AON_GPIO(S, 3), /* wake25 */ TEGRA_AON_GPIO(S, 4), /* wake26 */ TEGRA_AON_GPIO(S, 1), /* wake27 */ -EINVAL, /* wake28 */ TEGRA_AON_GPIO(FF, 0), /* wake29 */ TEGRA_AON_GPIO(FF, 4), /* wake30 */ -EINVAL, /* wake31 */ TEGRA_AON_GPIO(W, 2), /* wake32 */ TEGRA_AON_GPIO(W, 5), /* wake33 */ TEGRA_AON_GPIO(W, 1), /* wake34 */ TEGRA_AON_GPIO(V, 0), /* wake35 */ TEGRA_AON_GPIO(V, 1), /* wake36 */ TEGRA_AON_GPIO(V, 2), /* wake37 */ TEGRA_AON_GPIO(V, 3), /* wake38 */ TEGRA_AON_GPIO(V, 4), /* wake39 */ TEGRA_AON_GPIO(V, 5), /* wake40 */ TEGRA_AON_GPIO(EE, 0), /* wake41 */ TEGRA_AON_GPIO(Z, 1), /* wake42 */ TEGRA_AON_GPIO(Z, 3), /* wake43 */ TEGRA_AON_GPIO(AA, 0), /* wake44 */ TEGRA_AON_GPIO(AA, 1), /* wake45 */ TEGRA_AON_GPIO(AA, 2), /* wake46 */ TEGRA_AON_GPIO(AA, 3), /* wake47 */ TEGRA_AON_GPIO(AA, 4), /* wake48 */ TEGRA_AON_GPIO(AA, 5), /* wake49 */ TEGRA_AON_GPIO(AA, 6), /* wake50 */ TEGRA_AON_GPIO(AA, 7), /* wake51 */ -EINVAL, /* wake52 */ -EINVAL, /* wake53 */ -EINVAL, /* wake54 */ -EINVAL, /* wake55 */ -EINVAL, /* wake56 */ -EINVAL, /* wake57 */ -EINVAL, /* wake58 */ -EINVAL, /* wake59 */ -EINVAL, /* wake60 */ -EINVAL, /* wake61 */ -EINVAL, /* wake62 */ -EINVAL, /* wake63 */ -EINVAL, /* wake64 */ TEGRA_AON_GPIO(Z, 0), /* wake65 */ TEGRA_AON_GPIO(Z, 2), /* wake66 */ TEGRA_AON_GPIO(FF, 1), /* wake67 */ TEGRA_AON_GPIO(FF, 2), /* wake68 */ TEGRA_AON_GPIO(FF, 3), /* wake69 */ -EINVAL, /* wake70 */ -EINVAL, /* wake71 */ -EINVAL, /* wake72 */ -EINVAL, /* wake73 */ -EINVAL, /* wake74 */ -EINVAL, /* wake75 */ -EINVAL, /* wake76 */ -EINVAL, /* wake77 */ -EINVAL, /* wake78 */ -EINVAL, /* wake79 */ -EINVAL, /* wake80 */ -EINVAL, /* wake81 */ -EINVAL, /* wake82 */ -EINVAL, /* wake83 */ -EINVAL, /* wake84 */ -EINVAL, /* wake85 */ -EINVAL, /* wake86 */ -EINVAL, /* wake87 */ -EINVAL, /* wake88 */ -EINVAL, /* wake89 */ -EINVAL, /* wake90 */ -EINVAL, /* wake91 */ -EINVAL, /* wake92 */ -EINVAL, /* wake93 */ -EINVAL, /* wake94 */ -EINVAL, /* wake95 */ }; struct tegra_gpio_port_soc_info { const char *port_name; int cont_id; int port_index; int valid_pins; int reg_index; int scr_offset; u32 reg_offset; }; #define TEGRA_MAIN_GPIO_PORT_INFO(port, cid, cind, npins) \ [TEGRA_MAIN_GPIO_PORT_##port] = { \ .port_name = #port, \ .cont_id = cid, \ .port_index = cind, \ .valid_pins = npins, \ .reg_index = 0, \ .scr_offset = cid * 0x1000 + cind * 0x40, \ .reg_offset = cid * 0x1000 + cind * 0x200, \ } #define TEGRA_AON_GPIO_PORT_INFO(port, cid, cind, npins) \ [TEGRA_AON_GPIO_PORT_##port] = { \ .port_name = #port, \ .cont_id = cid, \ .port_index = cind, \ .valid_pins = npins, \ .reg_index = 1, \ .scr_offset = cind * 0x40, \ .reg_offset = cind * 0x200, \ } static struct tegra_gpio_port_soc_info tegra186_gpio_cinfo[] = { TEGRA_MAIN_GPIO_PORT_INFO(A, 2, 0, 7), TEGRA_MAIN_GPIO_PORT_INFO(B, 3, 0, 7), TEGRA_MAIN_GPIO_PORT_INFO(C, 3, 1, 7), TEGRA_MAIN_GPIO_PORT_INFO(D, 3, 2, 6), TEGRA_MAIN_GPIO_PORT_INFO(E, 2, 1, 8), TEGRA_MAIN_GPIO_PORT_INFO(F, 2, 2, 6), TEGRA_MAIN_GPIO_PORT_INFO(G, 4, 1, 6), TEGRA_MAIN_GPIO_PORT_INFO(H, 1, 0, 7), TEGRA_MAIN_GPIO_PORT_INFO(I, 0, 4, 8), TEGRA_MAIN_GPIO_PORT_INFO(J, 5, 0, 8), TEGRA_MAIN_GPIO_PORT_INFO(K, 5, 1, 1), TEGRA_MAIN_GPIO_PORT_INFO(L, 1, 1, 8), TEGRA_MAIN_GPIO_PORT_INFO(M, 5, 3, 6), TEGRA_MAIN_GPIO_PORT_INFO(N, 0, 0, 7), TEGRA_MAIN_GPIO_PORT_INFO(O, 0, 1, 4), TEGRA_MAIN_GPIO_PORT_INFO(P, 4, 0, 7), TEGRA_MAIN_GPIO_PORT_INFO(Q, 0, 2, 6), TEGRA_MAIN_GPIO_PORT_INFO(R, 0, 5, 6), TEGRA_MAIN_GPIO_PORT_INFO(T, 0, 3, 4), TEGRA_MAIN_GPIO_PORT_INFO(X, 1, 2, 8), TEGRA_MAIN_GPIO_PORT_INFO(Y, 1, 3, 7), TEGRA_MAIN_GPIO_PORT_INFO(BB, 2, 3, 2), TEGRA_MAIN_GPIO_PORT_INFO(CC, 5, 2, 4), TEGRA_MAIN_GPIO_PORT_INFO(DD, -1, -1, 0), }; static struct tegra_gpio_port_soc_info tegra186_aon_gpio_cinfo[] = { TEGRA_AON_GPIO_PORT_INFO(S, 0, 1, 5), TEGRA_AON_GPIO_PORT_INFO(U, 0, 2, 6), TEGRA_AON_GPIO_PORT_INFO(V, 0, 4, 8), TEGRA_AON_GPIO_PORT_INFO(W, 0, 5, 8), TEGRA_AON_GPIO_PORT_INFO(Z, 0, 7, 4), TEGRA_AON_GPIO_PORT_INFO(AA, 0, 6, 8), TEGRA_AON_GPIO_PORT_INFO(EE, 0, 3, 3), TEGRA_AON_GPIO_PORT_INFO(FF, 0, 0, 5), }; #define TEGRA194_MAIN_GPIO_PORT_INFO(port, cid, cind, npins) \ [TEGRA194_MAIN_GPIO_PORT_##port] = { \ .port_name = #port, \ .cont_id = cid, \ .port_index = cind, \ .valid_pins = npins, \ .reg_index = 0, \ .scr_offset = cid * 0x1000 + cind * 0x40, \ .reg_offset = cid * 0x1000 + cind * 0x200, \ } #define TEGRA194_AON_GPIO_PORT_INFO(port, cid, cind, npins) \ [TEGRA194_AON_GPIO_PORT_##port] = { \ .port_name = #port, \ .cont_id = cid, \ .port_index = cind, \ .valid_pins = npins, \ .reg_index = 1, \ .scr_offset = cind * 0x40, \ .reg_offset = cind * 0x200, \ } static const int tegra194_gpio_wakes[] = { TEGRA194_MAIN_GPIO(K, 4), /* wake0 */ TEGRA194_MAIN_GPIO(L, 2), /* wake1 */ -EINVAL, /* wake2 */ TEGRA194_MAIN_GPIO(J, 3), /* wake3 */ TEGRA194_MAIN_GPIO(N, 1), /* wake4 */ TEGRA194_MAIN_GPIO(O, 3), /* wake5 */ -EINVAL, /* wake6 */ TEGRA194_MAIN_GPIO(H, 6), /* wake7 */ TEGRA194_MAIN_GPIO(G, 7), /* wake8 */ TEGRA194_MAIN_GPIO(H, 1), /* wake9 */ -EINVAL, /* wake10 */ TEGRA194_MAIN_GPIO(C, 5), /* wake11 */ TEGRA194_MAIN_GPIO(S, 5), /* wake12 */ TEGRA194_MAIN_GPIO(S, 6), /* wake13 */ -EINVAL, /* wake14 */ TEGRA194_MAIN_GPIO(T, 0), /* wake15 */ TEGRA194_MAIN_GPIO(V, 1), /* wake16 */ TEGRA194_MAIN_GPIO(F, 4), /* wake17 */ TEGRA194_MAIN_GPIO(C, 7), /* wake18 */ TEGRA194_MAIN_GPIO(D, 3), /* wake19 */ TEGRA194_MAIN_GPIO(G, 4), /* wake20 */ -EINVAL, /* wake21 */ TEGRA194_MAIN_GPIO(P, 3), /* wake22 */ TEGRA194_MAIN_GPIO(C, 1), /* wake23 */ -EINVAL, /* wake24 */ -EINVAL, /* wake25 */ -EINVAL, /* wake26 */ -EINVAL, /* wake27 */ TEGRA194_MAIN_GPIO(F, 2), /* wake28 */ -EINVAL, /* wake29 */ TEGRA194_MAIN_GPIO(G, 3), /* wake30 */ TEGRA194_MAIN_GPIO(I, 4), /* wake31 */ -EINVAL, /* wake32 */ TEGRA194_MAIN_GPIO(R, 5), /* wake33 */ TEGRA194_MAIN_GPIO(P, 4), /* wake34 */ TEGRA194_MAIN_GPIO(Q, 0), /* wake35 */ TEGRA194_MAIN_GPIO(P, 5), /* wake36 */ TEGRA194_MAIN_GPIO(P, 6), /* wake37 */ TEGRA194_MAIN_GPIO(Q, 3), /* wake38 */ -EINVAL, /* wake39 */ TEGRA194_MAIN_GPIO(Q, 1), /* wake40 */ -EINVAL, /* wake41 */ -EINVAL, /* wake42 */ -EINVAL, /* wake43 */ TEGRA194_MAIN_GPIO(Y, 0), /* wake44 */ TEGRA194_MAIN_GPIO(Z, 6), /* wake45 */ -EINVAL, /* wake46 */ -EINVAL, /* wake47 */ -EINVAL, /* wake48 */ -EINVAL, /* wake49 */ TEGRA194_MAIN_GPIO(Z, 7), /* wake50 */ TEGRA194_MAIN_GPIO(Q, 2), /* wake51 */ TEGRA194_MAIN_GPIO(X, 7), /* wake52 */ TEGRA194_MAIN_GPIO(Z, 0), /* wake53 */ TEGRA194_MAIN_GPIO(K, 2), /* wake54 */ TEGRA194_MAIN_GPIO(L, 0), /* wake55 */ TEGRA194_MAIN_GPIO(Y, 3), /* wake56 */ TEGRA194_MAIN_GPIO(L, 3), /* wake57 */ TEGRA194_MAIN_GPIO(Y, 4), /* wake58 */ TEGRA194_MAIN_GPIO(M, 7), /* wake59 */ TEGRA194_MAIN_GPIO(M, 0), /* wake60 */ TEGRA194_MAIN_GPIO(Z, 1), /* wake61 */ TEGRA194_MAIN_GPIO(Z, 2), /* wake62 */ TEGRA194_MAIN_GPIO(M, 1), /* wake63 */ TEGRA194_MAIN_GPIO(N, 2), /* wake64 */ TEGRA194_MAIN_GPIO(K, 6), /* wake65 */ TEGRA194_MAIN_GPIO(M, 3), /* wake66 */ TEGRA194_MAIN_GPIO(G, 0), /* wake67 */ TEGRA194_MAIN_GPIO(G, 1), /* wake68 */ TEGRA194_MAIN_GPIO(G, 2), /* wake69 */ TEGRA194_MAIN_GPIO(M, 4), /* wake70 */ TEGRA194_MAIN_GPIO(M, 2), /* wake71 */ -EINVAL, /* wake72 */ -EINVAL, /* wake73 */ -EINVAL, /* wake74 */ -EINVAL, /* wake75 */ -EINVAL, /* wake76 */ -EINVAL, /* wake77 */ -EINVAL, /* wake78 */ -EINVAL, /* wake79 */ -EINVAL, /* wake80 */ -EINVAL, /* wake81 */ -EINVAL, /* wake82 */ -EINVAL, /* wake83 */ -EINVAL, /* wake84 */ -EINVAL, /* wake85 */ -EINVAL, /* wake86 */ -EINVAL, /* wake87 */ -EINVAL, /* wake88 */ -EINVAL, /* wake89 */ -EINVAL, /* wake90 */ -EINVAL, /* wake91 */ -EINVAL, /* wake92 */ -EINVAL, /* wake93 */ -EINVAL, /* wake94 */ -EINVAL, /* wake95 */ }; static const int tegra194_aon_gpio_wakes[] = { -EINVAL, /* wake0 */ -EINVAL, /* wake1 */ TEGRA194_AON_GPIO(EE, 2), /* wake2 */ -EINVAL, /* wake3 */ -EINVAL, /* wake4 */ -EINVAL, /* wake5 */ -EINVAL, /* wake6 */ -EINVAL, /* wake7 */ -EINVAL, /* wake8 */ -EINVAL, /* wake9 */ TEGRA194_AON_GPIO(EE, 3), /* wake10 */ -EINVAL, /* wake11 */ -EINVAL, /* wake12 */ -EINVAL, /* wake13 */ -EINVAL, /* wake14 */ -EINVAL, /* wake15 */ -EINVAL, /* wake16 */ -EINVAL, /* wake17 */ -EINVAL, /* wake18 */ -EINVAL, /* wake19 */ -EINVAL, /* wake20 */ TEGRA194_AON_GPIO(DD, 2), /* wake21 */ -EINVAL, /* wake22 */ -EINVAL, /* wake23 */ -EINVAL, /* wake24 */ TEGRA194_AON_GPIO(EE, 0), /* wake25 */ TEGRA194_AON_GPIO(EE, 1), /* wake26 */ TEGRA194_AON_GPIO(EE, 6), /* wake27 */ -EINVAL, /* wake28 */ TEGRA194_AON_GPIO(EE, 4), /* wake29 */ -EINVAL, /* wake30 */ -EINVAL, /* wake31 */ -EINVAL, /* wake32 */ -EINVAL, /* wake33 */ -EINVAL, /* wake34 */ -EINVAL, /* wake35 */ -EINVAL, /* wake36 */ -EINVAL, /* wake37 */ -EINVAL, /* wake38 */ TEGRA194_AON_GPIO(CC, 3), /* wake39 */ -EINVAL, /* wake40 */ TEGRA194_AON_GPIO(DD, 0), /* wake41 */ TEGRA194_AON_GPIO(AA, 1), /* wake42 */ TEGRA194_AON_GPIO(AA, 3), /* wake43 */ -EINVAL, /* wake44 */ -EINVAL, /* wake45 */ TEGRA194_AON_GPIO(AA, 6), /* wake46 */ TEGRA194_AON_GPIO(BB, 3), /* wake47 */ TEGRA194_AON_GPIO(BB, 2), /* wake48 */ TEGRA194_AON_GPIO(AA, 7), /* wake49 */ -EINVAL, /* wake50 */ -EINVAL, /* wake51 */ -EINVAL, /* wake52 */ -EINVAL, /* wake53 */ -EINVAL, /* wake54 */ -EINVAL, /* wake55 */ -EINVAL, /* wake56 */ -EINVAL, /* wake57 */ -EINVAL, /* wake58 */ -EINVAL, /* wake59 */ -EINVAL, /* wake60 */ -EINVAL, /* wake61 */ -EINVAL, /* wake62 */ -EINVAL, /* wake63 */ -EINVAL, /* wake64 */ -EINVAL, /* wake65 */ -EINVAL, /* wake66 */ -EINVAL, /* wake67 */ -EINVAL, /* wake68 */ -EINVAL, /* wake69 */ -EINVAL, /* wake70 */ -EINVAL, /* wake71 */ -EINVAL, /* wake72 */ -EINVAL, /* wake73 */ -EINVAL, /* wake74 */ -EINVAL, /* wake75 */ -EINVAL, /* wake76 */ -EINVAL, /* wake77 */ -EINVAL, /* wake78 */ -EINVAL, /* wake79 */ -EINVAL, /* wake80 */ -EINVAL, /* wake81 */ -EINVAL, /* wake82 */ -EINVAL, /* wake83 */ -EINVAL, /* wake84 */ -EINVAL, /* wake85 */ -EINVAL, /* wake86 */ -EINVAL, /* wake87 */ -EINVAL, /* wake88 */ -EINVAL, /* wake89 */ -EINVAL, /* wake90 */ -EINVAL, /* wake91 */ -EINVAL, /* wake92 */ -EINVAL, /* wake93 */ -EINVAL, /* wake94 */ -EINVAL, /* wake95 */ }; static struct tegra_gpio_port_soc_info tegra194_gpio_cinfo[] = { TEGRA194_MAIN_GPIO_PORT_INFO(A, 1, 2, 8), TEGRA194_MAIN_GPIO_PORT_INFO(B, 4, 7, 2), TEGRA194_MAIN_GPIO_PORT_INFO(C, 4, 3, 8), TEGRA194_MAIN_GPIO_PORT_INFO(D, 4, 4, 4), TEGRA194_MAIN_GPIO_PORT_INFO(E, 4, 5, 8), TEGRA194_MAIN_GPIO_PORT_INFO(F, 4, 6, 6), TEGRA194_MAIN_GPIO_PORT_INFO(G, 4, 0, 8), TEGRA194_MAIN_GPIO_PORT_INFO(H, 4, 1, 8), TEGRA194_MAIN_GPIO_PORT_INFO(I, 4, 2, 5), TEGRA194_MAIN_GPIO_PORT_INFO(J, 5, 1, 6), TEGRA194_MAIN_GPIO_PORT_INFO(K, 3, 0, 8), TEGRA194_MAIN_GPIO_PORT_INFO(L, 3, 1, 4), TEGRA194_MAIN_GPIO_PORT_INFO(M, 2, 3, 8), TEGRA194_MAIN_GPIO_PORT_INFO(N, 2, 4, 3), TEGRA194_MAIN_GPIO_PORT_INFO(O, 5, 0, 6), TEGRA194_MAIN_GPIO_PORT_INFO(P, 2, 5, 8), TEGRA194_MAIN_GPIO_PORT_INFO(Q, 2, 6, 8), TEGRA194_MAIN_GPIO_PORT_INFO(R, 2, 7, 6), TEGRA194_MAIN_GPIO_PORT_INFO(S, 3, 3, 8), TEGRA194_MAIN_GPIO_PORT_INFO(T, 3, 4, 8), TEGRA194_MAIN_GPIO_PORT_INFO(U, 3, 5, 1), TEGRA194_MAIN_GPIO_PORT_INFO(V, 1, 0, 8), TEGRA194_MAIN_GPIO_PORT_INFO(W, 1, 1, 2), TEGRA194_MAIN_GPIO_PORT_INFO(X, 2, 0, 8), TEGRA194_MAIN_GPIO_PORT_INFO(Y, 2, 1, 8), TEGRA194_MAIN_GPIO_PORT_INFO(Z, 2, 2, 8), TEGRA194_MAIN_GPIO_PORT_INFO(FF, 3, 2, 2), TEGRA194_MAIN_GPIO_PORT_INFO(GG, 0, 0, 2), }; static struct tegra_gpio_port_soc_info tegra194_aon_gpio_cinfo[] = { TEGRA194_AON_GPIO_PORT_INFO(AA, 0, 3, 8), TEGRA194_AON_GPIO_PORT_INFO(BB, 0, 4, 4), TEGRA194_AON_GPIO_PORT_INFO(CC, 0, 1, 8), TEGRA194_AON_GPIO_PORT_INFO(DD, 0, 2, 3), TEGRA194_AON_GPIO_PORT_INFO(EE, 0, 0, 7), }; struct tegra_gpio_info; struct tegra_gpio_soc_info { const char *name; const char *debug_fs_name; const struct tegra_gpio_port_soc_info *port; int nports; const int *wake_table; int nwakes; const struct tegra_gte_info *gte_info; int gte_npins; int num_irq_line; int num_banks; int start_irq_line; bool do_vm_check; }; struct tegra_gpio_irq_info { int hw_irq; int sw_irq; bool valid; u32 irq_map[MAX_GPIO_PORTS];; }; struct tegra_gpio_controller { int bank; int irq[MAX_IRQS]; struct tegra_gpio_info *tgi; struct tegra_gpio_irq_info irq_info[MAX_IRQS]; unsigned long int_state[MAX_GPIO_IRQS]; int num_ports; }; struct tegra_gpio_state { bool restore_needed; u32 val; u32 conf; u32 out; }; struct tegra_gpio_info { struct device *dev; int nbanks; void __iomem *gpio_regs; void __iomem *scr_regs; void __iomem *gte_regs; struct irq_domain *irq_domain; const struct tegra_gpio_soc_info *soc; struct tegra_gpio_controller tg_contrlr[MAX_GPIO_CONTROLLERS]; struct gpio_chip gc; struct irq_chip ic; struct tegra_gpio_state *state_suspend; struct tegra_gpio_state *state_init; unsigned int gte_enable; bool use_timestamp; bool use_ext_gte_timestamp; }; static struct lock_class_key gpio_lock_class; /*************************** GTE related code ********************/ struct tegra_gte_info { uint32_t pin_num; uint32_t slice; uint32_t slice_bit; }; /* Structure to maintain all information about the AON GPIOs * that can be supported */ static struct tegra_gte_info tegra194_gte_info[] = { /* pin_num, slice, slice_bit*/ [0] = {11, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_0}, [1] = {10, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_1}, [2] = {9, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_2}, [3] = {8, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_3}, [4] = {7, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_4}, [5] = {6, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_5}, [6] = {5, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_6}, [7] = {4, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_7}, [8] = {3, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_8}, [9] = {2, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_9}, [10] = {1, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_10}, [11] = {0, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_11}, [12] = {26, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_12}, [13] = {25, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_13}, [14] = {24, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_14}, [15] = {23, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_15}, [16] = {22, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_16}, [17] = {21, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_17}, [18] = {20, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_18}, [19] = {19, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_19}, [20] = {18, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_20}, [21] = {17, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_21}, [22] = {16, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_22}, [23] = {38, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_23}, [24] = {37, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_24}, [25] = {36, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_25}, [26] = {35, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_26}, [27] = {34, 2, NV_AON_GTE_SLICE2_IRQ_GPIO_27}, [28] = {33, 1, NV_AON_GTE_SLICE1_IRQ_GPIO_28}, [29] = {32, 1, NV_AON_GTE_SLICE1_IRQ_GPIO_29}, }; static inline u32 tegra_gte_readl(struct tegra_gpio_info *tgi, u32 reg) { return __raw_readl(tgi->gte_regs + reg); } static inline void tegra_gte_writel(struct tegra_gpio_info *tgi, u32 reg, u32 val) { __raw_writel(val, tgi->gte_regs + reg); } static void tegra_gte_flush_fifo(struct tegra_gpio_info *tgi) { /* Check if FIFO is empty */ while ((tegra_gte_readl(tgi, GTE_GPIO_TESTATUS) >> GTE_GPIO_TESTATUS_OCCUPANCY_SHIFT) & GTE_GPIO_TESTATUS_OCCUPANCY_MASK) { /* Pop this entry, go to next */ tegra_gte_writel(tgi, GTE_GPIO_TECMD, GTE_GPIO_TECMD_CMD_POP); } } u64 tegra_gte_read_fifo(struct tegra_gpio_info *tgi, u32 offset) { u32 src_slice; u32 tsh, tsl; u64 ts = 0; u32 precv, curcv, xorcv; u32 aon_bits; u32 bit_index = 0; /* Check if FIFO is empty */ while ((tegra_gte_readl(tgi, GTE_GPIO_TESTATUS) >> GTE_GPIO_TESTATUS_OCCUPANCY_SHIFT) & GTE_GPIO_TESTATUS_OCCUPANCY_MASK) { src_slice = (tegra_gte_readl(tgi, GTE_GPIO_TESRC) >> GTE_GPIO_TESRC_SLICE_SHIFT) & GTE_GPIO_TESRC_SLICE_DEFAULT_MASK; if (src_slice == AON_GPIO_SLICE1_INDEX || src_slice == AON_GPIO_SLICE2_INDEX) { precv = tegra_gte_readl(tgi, GTE_GPIO_TEPCV); curcv = tegra_gte_readl(tgi, GTE_GPIO_TECCV); /* Save TSC high and low 32 bits value */ tsh = tegra_gte_readl(tgi, GTE_GPIO_TETSCH); tsl = tegra_gte_readl(tgi, GTE_GPIO_TETSCL); /* TSC countre as 64 bits */ ts = (((uint64_t)tsh << 32) | tsl); xorcv = precv ^ curcv; if (src_slice == AON_GPIO_SLICE1_INDEX) aon_bits = xorcv & AON_GPIO_SLICE1_MAP; else aon_bits = xorcv & AON_GPIO_SLICE2_MAP; bit_index = ffs(aon_bits) - 1; } /* Pop this entry, go to next */ tegra_gte_writel(tgi, GTE_GPIO_TECMD, GTE_GPIO_TECMD_CMD_POP); tegra_gte_readl(tgi, GTE_GPIO_TESRC); } return (tgi->soc->gte_info[bit_index].pin_num == offset) ? ts : 0; } int tegra_gte_enable_ts(struct tegra_gpio_info *tgi, u32 offset) { u32 val, mask, reg; int i = 0; if (tgi->gte_enable == 1) { dev_err(tgi->dev, "timestamp is already enabled for gpio\n"); return -EINVAL; } /* Configure Timestamping AON GPIO to SLICEx mapping */ for (i = 0; i < tgi->soc->gte_npins; i++) { if (tgi->soc->gte_info[i].pin_num == offset) { reg = (tgi->soc->gte_info[i].slice * GTE_GPIO_SLICE_SIZE) + GTE_GPIO_SLICE0_TETEN; val = (1 << tgi->soc->gte_info[i].slice_bit); tegra_gte_writel(tgi, reg, val); break; } } val = tegra_gte_readl(tgi, GTE_GPIO_TECTRL); mask = (GTE_GPIO_TECTRL_ENABLE_MASK << GTE_GPIO_TECTRL_ENABLE_SHIFT); val &= ~mask; val |= (GTE_GPIO_TECTRL_ENABLE_ENABLE << GTE_GPIO_TECTRL_ENABLE_SHIFT); tegra_gte_writel(tgi, GTE_GPIO_TECTRL, val); tegra_gte_flush_fifo(tgi); tgi->gte_enable = 1; return 0; } int tegra_gte_disable_ts(struct tegra_gpio_info *tgi, u32 offset) { u32 val, mask; if (tgi->gte_enable == 0) { dev_err(tgi->dev, "timestamp is already disabled\n"); return 0; } val = tegra_gte_readl(tgi, GTE_GPIO_TECTRL); mask = (GTE_GPIO_TECTRL_ENABLE_MASK << GTE_GPIO_TECTRL_ENABLE_SHIFT); val &= ~mask; val |= (GTE_GPIO_TECTRL_ENABLE_DISABLE << GTE_GPIO_TECTRL_ENABLE_SHIFT); tegra_gte_writel(tgi, GTE_GPIO_TECTRL, val); /* Disable Slice mapping as well */ tegra_gte_writel(tgi, (AON_GPIO_SLICE1_INDEX * GTE_GPIO_SLICE_SIZE) + GTE_GPIO_SLICE0_TETEN, 0); tegra_gte_writel(tgi, (AON_GPIO_SLICE2_INDEX * GTE_GPIO_SLICE_SIZE) + GTE_GPIO_SLICE0_TETEN, 0); tgi->gte_enable = 0; return 0; } int tegra_gte_setup(struct tegra_gpio_info *tgi) { tegra_gte_writel(tgi, GTE_GPIO_TECTRL, 0); tgi->gte_enable = 0; return 0; } /*****************************************************************/ static int tegra186_gpio_to_wake(struct tegra_gpio_info *tgi, int gpio) { int i; for (i = 0; i < tgi->soc->nwakes; i++) { if (tgi->soc->wake_table[i] == gpio) { pr_info("gpio %s wake%d for gpio=%d(%s:%d)\n", tgi->soc->name, i, gpio, tgi->soc->port[GPIO_PORT(gpio)].port_name, GPIO_PIN(gpio)); return i; } } return -EINVAL; } #define GPIO_CNTRL_REG(tgi, gpio, roffset) \ ((tgi)->gpio_regs + (tgi)->soc->port[GPIO_PORT(gpio)].reg_offset + \ (GPIO_REG_DIFF * GPIO_PIN(gpio)) + (roffset)) static inline u32 tegra_gpio_readl(struct tegra_gpio_info *tgi, u32 gpio, u32 reg_offset) { return __raw_readl(GPIO_CNTRL_REG(tgi, gpio, reg_offset)); } static inline void tegra_gpio_writel(struct tegra_gpio_info *tgi, u32 val, u32 gpio, u32 reg_offset) { __raw_writel(val, GPIO_CNTRL_REG(tgi, gpio, reg_offset)); } static inline void tegra_gpio_update(struct tegra_gpio_info *tgi, u32 gpio, u32 reg_offset, u32 mask, u32 val) { u32 rval; rval = __raw_readl(GPIO_CNTRL_REG(tgi, gpio, reg_offset)); rval = (rval & ~mask) | (val & mask); __raw_writel(rval, GPIO_CNTRL_REG(tgi, gpio, reg_offset)); } /* This function will return if the GPIO is accessible by CPU */ static inline bool gpio_is_accessible(struct tegra_gpio_info *tgi, u32 offset) { int port = GPIO_PORT(offset); int pin = GPIO_PIN(offset); u32 val; int cont_id; u32 scr_offset = tgi->soc->port[port].scr_offset; if (pin >= tgi->soc->port[port].valid_pins) return false; cont_id = tgi->soc->port[port].cont_id; if (cont_id < 0) return false; if (tgi->soc->do_vm_check) { val = __raw_readl(tgi->scr_regs + scr_offset + (pin * GPIO_SCR_DIFF) + GPIO_VM_REG); if ((val & GPIO_VM_RW) != GPIO_VM_RW) return false; } val = __raw_readl(tgi->scr_regs + scr_offset + (pin * GPIO_SCR_DIFF) + GPIO_SCR_REG); if ((val & GPIO_SCR_SEC_ENABLE) == 0) return true; if ((val & GPIO_FULL_ACCESS) == GPIO_FULL_ACCESS) return true; return false; } static void tegra_gpio_save_gpio_state(struct tegra_gpio_info *tgi, u32 offset) { struct tegra_gpio_state *regs; regs = &tgi->state_init[offset]; regs->conf = tegra_gpio_readl(tgi, offset, GPIO_ENB_CONFIG_REG); regs->out = tegra_gpio_readl(tgi, offset, GPIO_OUT_CTRL_REG); regs->val = tegra_gpio_readl(tgi, offset, GPIO_OUT_VAL_REG); } static void tegra_gpio_restore_gpio_state(struct tegra_gpio_info *tgi, u32 offset) { struct tegra_gpio_state *regs; int was_gpio, was_output; regs = &tgi->state_init[offset]; was_gpio = regs->conf & 0x1; was_output = regs->conf & 0x2; /* * If pin was GPIO and pin direction was OUT then restore GPIO_OUT_VAL * first then GPIO_OUT_CTRL and then GPIO_CNF */ if (was_gpio & was_output) { tegra_gpio_writel(tgi, regs->val, offset, GPIO_OUT_VAL_REG); tegra_gpio_writel(tgi, regs->out, offset, GPIO_OUT_CTRL_REG); tegra_gpio_writel(tgi, regs->conf, offset, GPIO_ENB_CONFIG_REG); } /* * If pin was GPIO and pin direction was IN then restore GPIO_OUT_CTRL, * then GPIO_OUT_VAL and then GPIO_CNF */ else if (was_gpio) { tegra_gpio_writel(tgi, regs->out, offset, GPIO_OUT_CTRL_REG); tegra_gpio_writel(tgi, regs->val, offset, GPIO_OUT_VAL_REG); tegra_gpio_writel(tgi, regs->conf, offset, GPIO_ENB_CONFIG_REG); } /* * If pin is SFIO then restore GPIO_CNF, then GPIO_OUT_CTRL and then * GPIO_OUT_VAL */ else { tegra_gpio_writel(tgi, regs->conf, offset, GPIO_ENB_CONFIG_REG); tegra_gpio_writel(tgi, regs->out, offset, GPIO_OUT_CTRL_REG); tegra_gpio_writel(tgi, regs->val, offset, GPIO_OUT_VAL_REG); } } static void tegra_gpio_enable(struct tegra_gpio_info *tgi, int gpio) { tegra_gpio_update(tgi, gpio, GPIO_ENB_CONFIG_REG, GPIO_ENB_BIT, 0x1); } static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); if (!gpio_is_accessible(tgi, offset)) return -EBUSY; tegra_gpio_save_gpio_state(tgi, offset); return pinctrl_request_gpio(chip->base + offset); } static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); pinctrl_free_gpio(chip->base + offset); tegra_gpio_restore_gpio_state(tgi, offset); } static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); u32 val = (value) ? 0x1 : 0x0; tegra_gpio_writel(tgi, val, offset, GPIO_OUT_VAL_REG); } static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); u32 val; val = tegra_gpio_readl(tgi, offset, GPIO_ENB_CONFIG_REG); if (val & GPIO_INOUT_BIT) return tegra_gpio_readl(tgi, offset, GPIO_OUT_VAL_REG) & 0x1; return tegra_gpio_readl(tgi, offset, GPIO_INPUT_REG) & 0x1; } static void set_gpio_direction_mode(struct gpio_chip *chip, u32 offset, bool mode) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); u32 val; val = tegra_gpio_readl(tgi, offset, GPIO_ENB_CONFIG_REG); if (mode) val |= GPIO_INOUT_BIT; else val &= ~GPIO_INOUT_BIT; tegra_gpio_writel(tgi, val, offset, GPIO_ENB_CONFIG_REG); } static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); int ret; set_gpio_direction_mode(chip, offset, 0); tegra_gpio_enable(tgi, offset); ret = pinctrl_gpio_direction_input(chip->base + offset); if (ret < 0) dev_err(chip->parent, "Failed to set input direction: %d\n", ret); return ret; } static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); int ret; tegra_gpio_set(chip, offset, value); tegra_gpio_writel(tgi, 0, offset, GPIO_OUT_CTRL_REG); set_gpio_direction_mode(chip, offset, 1); tegra_gpio_enable(tgi, offset); ret = pinctrl_gpio_direction_output(chip->base + offset); if (ret < 0) dev_err(chip->parent, "Failed to set output direction: %d\n", ret); return ret; } int tegra_gpio_enable_external_gte(struct gpio_chip *chip) { struct tegra_gpio_info *tgi; if (!chip) return -EOPNOTSUPP; tgi = gpiochip_get_data(chip); tgi->use_ext_gte_timestamp = true; return 0; } static int tegra_gpio_timestamp_control(struct gpio_chip *chip, unsigned offset, int enable) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); u32 val = enable << GPIO_TIMESTAMP_FUNC_BIT; u32 mask = BIT(GPIO_TIMESTAMP_FUNC_BIT); int ret = 0; if (tgi->use_timestamp || tgi->use_ext_gte_timestamp) { tegra_gpio_update(tgi, offset, GPIO_ENB_CONFIG_REG, mask, val); if (tgi->use_timestamp) { if (enable) ret = tegra_gte_enable_ts(tgi, offset); else ret = tegra_gte_disable_ts(tgi, offset); } } else ret = -EOPNOTSUPP; return ret; } static int tegra_gpio_timestamp_read(struct gpio_chip *chip, unsigned offset, u64 *ts) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); int ret; if (tgi->use_timestamp) { *ts = tegra_gte_read_fifo(tgi, offset); ret = 0; } else ret = -EOPNOTSUPP; return ret; } static int tegra_gpio_suspend_configure(struct gpio_chip *chip, unsigned offset, enum gpiod_flags dflags) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); struct tegra_gpio_state *regs; if (!gpio_is_accessible(tgi, offset)) return -EBUSY; regs = &tgi->state_suspend[offset]; regs->conf = tegra_gpio_readl(tgi, offset, GPIO_ENB_CONFIG_REG), regs->out = tegra_gpio_readl(tgi, offset, GPIO_OUT_CTRL_REG), regs->val = tegra_gpio_readl(tgi, offset, GPIO_OUT_VAL_REG), pinctrl_gpio_save_config(tgi->gc.base + offset); regs->restore_needed = true; if (dflags & GPIOD_FLAGS_BIT_DIR_OUT) return tegra_gpio_direction_output(chip, offset, dflags & GPIOD_FLAGS_BIT_DIR_VAL); return tegra_gpio_direction_input(chip, offset); } static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned offset, unsigned debounce) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); unsigned dbc_ms = DIV_ROUND_UP(debounce, 1000); tegra_gpio_update(tgi, offset, GPIO_ENB_CONFIG_REG, GPIO_ENB_BIT, 0x1); tegra_gpio_update(tgi, offset, GPIO_ENB_CONFIG_REG, GPIO_DEB_FUNC_BIT, GPIO_DEB_FUNC_BIT); /* Update debounce threshold, GPIO controller support maximum * 255ms debounce */ if (dbc_ms > 255) dbc_ms = 255; tegra_gpio_writel(tgi, dbc_ms, offset, GPIO_DBC_THRES_REG); return 0; } #if KERNEL_VERSION(4, 13, 0) < LINUX_VERSION_CODE static int tegra_gpio_set_config(struct gpio_chip *chip, unsigned offset, unsigned long config) { if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) return -ENOTSUPP; tegra_gpio_set_debounce(chip, offset, pinconf_to_config_argument(config)); return 0; } #endif static int tegra_gpio_is_enabled(struct gpio_chip *chip, unsigned offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); u32 val; if (!gpio_is_accessible(tgi, offset)) return -EPERM; val = tegra_gpio_readl(tgi, offset, GPIO_ENB_CONFIG_REG); return !!(val & GPIO_ENB_BIT); } static int tegra_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); u32 val; if (!gpio_is_accessible(tgi, offset)) return -EPERM; val = tegra_gpio_readl(tgi, offset, GPIO_ENB_CONFIG_REG); val &= GPIO_INOUT_BIT; return !val; } static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); return irq_find_mapping(tgi->irq_domain, offset); } static void tegra_gpio_irq_ack(struct irq_data *d) { struct tegra_gpio_controller *ctrlr = irq_data_get_irq_chip_data(d); tegra_gpio_writel(ctrlr->tgi, 1, d->hwirq, GPIO_INT_CLEAR_REG); } static void tegra_gpio_irq_mask(struct irq_data *d) { struct tegra_gpio_controller *c = irq_data_get_irq_chip_data(d); tegra_gpio_update(c->tgi, d->hwirq, GPIO_ENB_CONFIG_REG, GPIO_INT_FUNC_BIT, 0); c->int_state[d->hwirq] &= ~GPIO_INTERRUPT_UNMASK_ENABLE; } static void tegra_gpio_irq_unmask(struct irq_data *d) { struct tegra_gpio_controller *c = irq_data_get_irq_chip_data(d); tegra_gpio_update(c->tgi, d->hwirq, GPIO_ENB_CONFIG_REG, GPIO_INT_FUNC_BIT, GPIO_INT_FUNC_BIT); c->int_state[d->hwirq] |= GPIO_INTERRUPT_UNMASK_ENABLE; } static void tegra_gpio_irq_bus_sync_unlock(struct irq_data *d) { struct tegra_gpio_controller *c = irq_data_get_irq_chip_data(d); struct gpio_chip *chip = &c->tgi->gc; int ret; if (!(c->int_state[d->hwirq] & GPIO_INTERRUPT_UNMASK_ENABLE)) return; if (c->int_state[d->hwirq] & GPIO_PIN_DIRECTION_INPUT) return; ret = tegra_gpio_direction_input(chip, d->hwirq); if (ret < 0) { dev_err(chip->parent, "Failed to set input direction for pin %lu: %d\n", d->hwirq, ret); return; } c->int_state[d->hwirq] |= GPIO_PIN_DIRECTION_INPUT; } static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct tegra_gpio_controller *ctrlr = irq_data_get_irq_chip_data(d); int gpio = d->hwirq; u32 lvl_type; u32 trg_type; u32 val; int wake = tegra186_gpio_to_wake(ctrlr->tgi, d->hwirq); switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_RISING: trg_type = TRIGGER_LEVEL_HIGH; lvl_type = GPIO_INT_LVL_SINGLE_EDGE_TRIGGER; break; case IRQ_TYPE_EDGE_FALLING: trg_type = TRIGGER_LEVEL_LOW; lvl_type = GPIO_INT_LVL_SINGLE_EDGE_TRIGGER; break; case IRQ_TYPE_EDGE_BOTH: lvl_type = GPIO_INT_LVL_BOTH_EDGE_TRIGGER; trg_type = 0; break; case IRQ_TYPE_LEVEL_HIGH: trg_type = TRIGGER_LEVEL_HIGH; lvl_type = GPIO_INT_LVL_LEVEL_TRIGGER; break; case IRQ_TYPE_LEVEL_LOW: trg_type = TRIGGER_LEVEL_LOW; lvl_type = GPIO_INT_LVL_LEVEL_TRIGGER; break; default: return -EINVAL; } trg_type = trg_type << 0x4; lvl_type = lvl_type << 0x2; /* Clear and Program the values */ val = tegra_gpio_readl(ctrlr->tgi, gpio, GPIO_ENB_CONFIG_REG); val &= ~((0x3 << GPIO_TRG_TYPE_BIT_OFFSET) | (GPIO_TRG_LVL_BIT)); val |= trg_type | lvl_type; tegra_gpio_writel(ctrlr->tgi, val, gpio, GPIO_ENB_CONFIG_REG); tegra_gpio_enable(ctrlr->tgi, gpio); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) irq_set_handler_locked(d, handle_edge_irq); if (wake >= 0) tegra_pm_irq_set_wake_type(wake, type); return 0; } static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) { struct tegra_gpio_controller *ctrlr = irq_data_get_irq_chip_data(d); int wake = tegra186_gpio_to_wake(ctrlr->tgi, d->hwirq); int ret; if (wake < 0) return wake; ret = tegra_pm_irq_set_wake(wake, enable); if (ret) pr_err("Failed gpio lp0 %s for irq=%d, error=%d\n", (enable ? "enable" : "disable"), d->irq, ret); return ret; } static void tegra_gpio_irq_handler_desc(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct tegra_gpio_controller *tg_cont = irq_desc_get_handler_data(desc); struct tegra_gpio_info *tgi = tg_cont->tgi; unsigned int irq = irq_desc_get_irq(desc); int pin; int port; int i; unsigned long val; u32 addr; int port_map[MAX_GPIO_PORTS]; unsigned int irq_offset, irq_index; for (i = 0; i < MAX_GPIO_PORTS; ++i) port_map[i] = -1; for (i = 0; i < tgi->soc->nports; ++i) { if (tgi->soc->port[i].cont_id == tg_cont->bank) port_map[tgi->soc->port[i].port_index] = i; } irq_index = 0; chained_irq_enter(chip, desc); if (tgi->soc->num_irq_line <= 1) goto single_line_irq; for (i = 0; i < tgi->soc->num_irq_line; i++) { irq_offset = i + tgi->soc->start_irq_line; if (!tg_cont->irq_info[irq_offset].valid) continue; if (tg_cont->irq_info[irq_offset].sw_irq == irq) { irq_index = irq_offset; break; } } if (i == tgi->soc->num_irq_line) { dev_err(tgi->dev, "IRQ %u is not mapped\n", irq); goto done; } single_line_irq: for (i = 0; i < MAX_GPIO_PORTS; i++) { port = port_map[i]; if (port == -1) continue; if (!(tg_cont->irq_info[irq_index].irq_map[i] & 0xFF)) continue; addr = tgi->soc->port[port].reg_offset; val = __raw_readl(tg_cont->tgi->gpio_regs + addr + GPIO_INT_STATUS_OFFSET + GPIO_STATUS_G1); for_each_set_bit(pin, &val, 8) generic_handle_irq(tegra_gpio_to_irq(&tgi->gc, port * 8 + pin)); } done: chained_irq_exit(chip, desc); } #ifdef CONFIG_DEBUG_FS #include #include static int dbg_gpio_show(struct seq_file *s, void *unused) { struct tegra_gpio_info *tgi = s->private; int i; seq_puts(s, "Port:Pin:ENB DBC IN OUT_CTRL OUT_VAL INT_CLR\n"); for (i = 0; i < tgi->gc.ngpio; i++) { if (!gpio_is_accessible(tgi, i)) continue; seq_printf(s, "%s:%d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", tgi->soc->port[GPIO_PORT(i)].port_name, i % 8, tegra_gpio_readl(tgi, i, GPIO_ENB_CONFIG_REG), tegra_gpio_readl(tgi, i, GPIO_DBC_THRES_REG), tegra_gpio_readl(tgi, i, GPIO_INPUT_REG), tegra_gpio_readl(tgi, i, GPIO_OUT_CTRL_REG), tegra_gpio_readl(tgi, i, GPIO_OUT_VAL_REG), tegra_gpio_readl(tgi, i, GPIO_INT_CLEAR_REG)); } return 0; } static int dbg_gpio_open(struct inode *inode, struct file *file) { return single_open(file, dbg_gpio_show, inode->i_private); } static const struct file_operations debug_fops = { .open = dbg_gpio_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int tegra_gpio_debuginit(struct tegra_gpio_info *tgi) { (void)debugfs_create_file(tgi->soc->debug_fs_name, S_IRUGO, NULL, tgi, &debug_fops); return 0; } #else static inline int tegra_gpio_debuginit(struct tegra_gpio_info *tgi) { return 0; } #endif static int tegra_gpio_get_num_ports(struct tegra_gpio_info *tgi, int bank) { int i; int count = 0; for (i = 0; i < tgi->soc->nports; i++) { if (tgi->soc->port[i].cont_id == bank) count++; } return count; } static void tegra_gpio_read_irq_routemap(struct tegra_gpio_info *tgi, int bank, int irq_count) { struct tegra_gpio_controller *tgcont = &tgi->tg_contrlr[bank]; int irq_offset = irq_count + tgi->soc->start_irq_line; int j; int ret; u32 pval; /* Port G interrupt is not mapped to any line. */ if (bank == 0) { ret = of_property_read_u32(tgi->dev->of_node, "port-GG-interrupt-line", &pval); if (!ret && (pval == irq_offset)) __raw_writel(0xF, tgi->scr_regs + (bank * 0x1000) + 0x800 + (0 * GPIO_REG_DIFF) + ROUTE_MAP_OFFSET + (irq_offset * 4)); } for (j = 0; j < tgcont->num_ports; j++) { tgcont->irq_info[irq_offset].irq_map[j] = __raw_readl(tgi->scr_regs + (bank * 0x1000) + 0x800 + (j * GPIO_REG_DIFF) + ROUTE_MAP_OFFSET + (irq_offset * 4)); } } static int tegra_gpio_to_hw_irq(unsigned int sw_irq) { struct irq_data *d = irq_get_irq_data(sw_irq); if (!d) return -ENODEV; return (int)irqd_to_hwirq(d) - 0x20; } static bool tegra_gpio_irq_is_protected(struct device *dev, u32 hw_irq) { struct device_node *np = dev->of_node; int count; int i; int ret; u32 pval; count = of_property_count_elems_of_size(np, "nvidia,protected-gpio-irqs", sizeof(u32)); if (count <= 0) return false; for (i = 0; i < count; ++i) { ret = of_property_read_u32_index(np, "nvidia,protected-gpio-irqs", i, &pval); if (ret < 0) return false; if (pval == hw_irq) return true; } return false; } static int tegra_gpio_probe(struct platform_device *pdev) { struct tegra_gpio_info *tgi; struct tegra_gpio_controller *tgcont; struct resource *res; struct device_node *np; u32 valid_map; int irq_offset; int hw_irq; int bank; int gpio; int ret; int i, j; tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL); if (!tgi) return -ENOMEM; tgi->dev = &pdev->dev; tgi->soc = of_device_get_match_data(&pdev->dev); if (!tgi->soc->num_banks) { for (bank = 0;; bank++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, bank); if (!res) break; } if (!bank) { dev_err(&pdev->dev, "No GPIO Controller found\n"); return -ENODEV; } tgi->nbanks = bank; } else { tgi->nbanks = tgi->soc->num_banks; } tgi->state_suspend = devm_kzalloc(&pdev->dev, tgi->soc->nports * 8 * sizeof(*tgi->state_suspend), GFP_KERNEL); if (!tgi->state_suspend) return -ENOMEM; tgi->state_init = devm_kzalloc(&pdev->dev, tgi->soc->nports * 8 * sizeof(*tgi->state_init), GFP_KERNEL); if (!tgi->state_init) return -ENOMEM; tgi->gc.label = tgi->soc->name; tgi->gc.request = tegra_gpio_request; tgi->gc.free = tegra_gpio_free; tgi->gc.direction_input = tegra_gpio_direction_input; tgi->gc.get = tegra_gpio_get; tgi->gc.direction_output = tegra_gpio_direction_output; tgi->gc.set = tegra_gpio_set; tgi->gc.get_direction = tegra_gpio_get_direction; tgi->gc.suspend_configure = tegra_gpio_suspend_configure; tgi->gc.is_enabled = tegra_gpio_is_enabled; tgi->gc.to_irq = tegra_gpio_to_irq; #if KERNEL_VERSION(4, 13, 0) < LINUX_VERSION_CODE tgi->gc.set_config = tegra_gpio_set_config; #else tgi->gc.set_debounce = tegra_gpio_set_debounce; #endif tgi->gc.timestamp_control = tegra_gpio_timestamp_control; tgi->gc.timestamp_read = tegra_gpio_timestamp_read; tgi->gc.base = -1; tgi->gc.ngpio = tgi->soc->nports * 8; tgi->gc.parent = &pdev->dev; tgi->gc.of_node = pdev->dev.of_node; tgi->ic.name = tgi->soc->name; tgi->ic.irq_ack = tegra_gpio_irq_ack; tgi->ic.irq_mask = tegra_gpio_irq_mask; tgi->ic.irq_unmask = tegra_gpio_irq_unmask; tgi->ic.irq_bus_sync_unlock = tegra_gpio_irq_bus_sync_unlock; tgi->ic.irq_set_type = tegra_gpio_irq_set_type; tgi->ic.irq_shutdown = tegra_gpio_irq_mask; tgi->ic.irq_set_wake = tegra_gpio_irq_set_wake; tgi->ic.irq_disable = tegra_gpio_irq_mask; platform_set_drvdata(pdev, tgi); tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node, tgi->gc.ngpio, &irq_domain_simple_ops, NULL); if (!tgi->irq_domain) return -ENODEV; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "security"); if (!res) { dev_err(&pdev->dev, "Missing security MEM resource\n"); return -ENODEV; } tgi->scr_regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(tgi->scr_regs)) { ret = PTR_ERR(tgi->scr_regs); dev_err(&pdev->dev, "Failed to iomap for security: %d\n", ret); return ret; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio"); if (!res) { dev_err(&pdev->dev, "Missing gpio MEM resource\n"); return -ENODEV; } tgi->gpio_regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(tgi->gpio_regs)) { ret = PTR_ERR(tgi->gpio_regs); dev_err(&pdev->dev, "Failed to iomap for gpio: %d\n", ret); return ret; } np = pdev->dev.of_node; if (!np) { dev_err(&pdev->dev, "No valid device node, probe failed\n"); return -EINVAL; } tgi->use_timestamp = of_property_read_bool(np, "use-timestamp"); if (tgi->use_timestamp) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gte"); if (!res) { dev_err(&pdev->dev, "Missing gte MEM resource\n"); return -ENODEV; } tgi->gte_regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(tgi->gte_regs)) { ret = PTR_ERR(tgi->gte_regs); dev_err(&pdev->dev, "Failed to iomap for gte: %d\n", ret); return ret; } } for (bank = 0; bank < tgi->nbanks; bank++) { tgcont = &tgi->tg_contrlr[bank]; tgcont->num_ports = tegra_gpio_get_num_ports(tgi, bank); for (i = 0; i < tgi->soc->num_irq_line; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i + (bank * tgi->soc->num_irq_line)); if (!res) { dev_err(&pdev->dev, "Missing IRQ resource\n"); return -ENODEV; } irq_offset = i + tgi->soc->start_irq_line; hw_irq = tegra_gpio_to_hw_irq(res->start); if (hw_irq < 0) { dev_err(&pdev->dev, "Failed to get HW IRQ of SW IRQ(%llu) :%d\n", res->start, hw_irq); return hw_irq; } tgcont->irq[irq_offset] = res->start; tgcont->irq_info[irq_offset].sw_irq = res->start; tgcont->irq_info[irq_offset].hw_irq = hw_irq; if (tegra_gpio_irq_is_protected(&pdev->dev, hw_irq)) { tgcont->irq_info[irq_offset].valid = false; continue; } /* read each port IRQ routemap */ if (tgi->soc->num_irq_line > 1) { tegra_gpio_read_irq_routemap(tgi, bank, i); } else { for (j = 0; j < MAX_GPIO_PORTS; ++j) tgcont->irq_info[i].irq_map[j] = 0xFF; } /* If no interrupt mapping then do not register IRQ */ valid_map = 0; for (j = 0; j < tgcont->num_ports; ++j) { valid_map |= tgcont->irq_info[irq_offset].irq_map[j]; valid_map &= 0xFF; } if (!valid_map) { tgcont->irq_info[irq_offset].valid = false; continue; } tgcont->irq_info[irq_offset].valid = true; } tgcont->bank = bank; tgcont->tgi = tgi; } ret = gpiochip_add_data(&tgi->gc, tgi); if (ret < 0) { dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); return ret; } for (gpio = 0; gpio < tgi->gc.ngpio; gpio++) { int cont_id = tgi->soc->port[GPIO_PORT(gpio)].cont_id; int irq; if (cont_id < 0) continue; irq = irq_create_mapping(tgi->irq_domain, gpio); if (gpio_is_accessible(tgi, gpio)) /* mask interrupts for this GPIO */ tegra_gpio_update(tgi, gpio, GPIO_ENB_CONFIG_REG, GPIO_INT_FUNC_BIT, 0); irq_set_lockdep_class(irq, &gpio_lock_class); irq_set_chip_data(irq, &tgi->tg_contrlr[cont_id]); irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq); } for (bank = 0; bank < tgi->nbanks; bank++) { tgcont = &tgi->tg_contrlr[bank]; for (i = 0; i < tgi->soc->num_irq_line; i++) { irq_offset = i + tgi->soc->start_irq_line; if (!tgcont->irq_info[irq_offset].valid) continue; irq_set_chained_handler_and_data( tgcont->irq_info[irq_offset].sw_irq, tegra_gpio_irq_handler_desc, tgcont); } } tegra_pm_update_gpio_wakeup_table(tgi->gc.base, (int *)tgi->soc->wake_table, tgi->soc->nwakes); if (tgi->use_timestamp) tegra_gte_setup(tgi); tegra_gpio_debuginit(tgi); return 0; } #ifdef CONFIG_PM_SLEEP static int tegra_gpio_resume_early(struct device *dev) { struct tegra_gpio_info *tgi = dev_get_drvdata(dev); struct tegra_gpio_state *regs; int i; for (i = 0; i < tgi->gc.ngpio; i++) { regs = &tgi->state_suspend[i]; if (!regs->restore_needed) continue; regs->restore_needed = false; tegra_gpio_writel(tgi, regs->val, i, GPIO_OUT_VAL_REG); tegra_gpio_writel(tgi, regs->out, i, GPIO_OUT_CTRL_REG); tegra_gpio_writel(tgi, regs->conf, i, GPIO_ENB_CONFIG_REG); pinctrl_gpio_restore_config(tgi->gc.base + i); } return 0; } static int tegra_gpio_suspend_late(struct device *dev) { struct tegra_gpio_info *tgi = dev_get_drvdata(dev); return of_gpiochip_suspend(&tgi->gc); } static const struct dev_pm_ops tegra_gpio_pm = { .suspend_late = tegra_gpio_suspend_late, .resume_early = tegra_gpio_resume_early, }; #define TEGRA_GPIO_PM &tegra_gpio_pm #else #define TEGRA_GPIO_PM NULL #endif static const struct tegra_gpio_soc_info t186_gpio_soc = { .name = "tegra-gpio", .debug_fs_name = "tegra_gpio", .port = tegra186_gpio_cinfo, .nports = ARRAY_SIZE(tegra186_gpio_cinfo), .wake_table = tegra186_gpio_wakes, .nwakes = ARRAY_SIZE(tegra186_gpio_wakes), .num_irq_line = 1, .num_banks = 0, .start_irq_line = 0, .do_vm_check = false, }; static const struct tegra_gpio_soc_info t186_aon_gpio_soc = { .name = "tegra-gpio-aon", .debug_fs_name = "tegra-gpio-aon", .port = tegra186_aon_gpio_cinfo, .nports = ARRAY_SIZE(tegra186_aon_gpio_cinfo), .wake_table = tegra186_aon_gpio_wakes, .nwakes = ARRAY_SIZE(tegra186_aon_gpio_wakes), .num_irq_line = 1, .num_banks = 0, .start_irq_line = 0, .do_vm_check = false, }; static const struct tegra_gpio_soc_info t194_gpio_soc = { .name = "tegra-gpio", .debug_fs_name = "tegra_gpio", .port = tegra194_gpio_cinfo, .nports = ARRAY_SIZE(tegra194_gpio_cinfo), .wake_table = tegra194_gpio_wakes, .nwakes = ARRAY_SIZE(tegra194_gpio_wakes), .num_irq_line = 8, .num_banks = 6, .start_irq_line = 0, .do_vm_check = true, }; static const struct tegra_gpio_soc_info t194_aon_gpio_soc = { .name = "tegra-gpio-aon", .debug_fs_name = "tegra-gpio-aon", .port = tegra194_aon_gpio_cinfo, .nports = ARRAY_SIZE(tegra194_aon_gpio_cinfo), .wake_table = tegra194_aon_gpio_wakes, .nwakes = ARRAY_SIZE(tegra194_aon_gpio_wakes), .gte_info = tegra194_gte_info, .gte_npins = ARRAY_SIZE(tegra194_gte_info), .num_irq_line = 4, .num_banks = 1, .start_irq_line = 4, .do_vm_check = false, }; static struct of_device_id tegra_gpio_of_match[] = { { .compatible = "nvidia,tegra186-gpio", .data = &t186_gpio_soc}, { .compatible = "nvidia,tegra186-gpio-aon", .data = &t186_aon_gpio_soc}, { .compatible = "nvidia,tegra194-gpio", .data = &t194_gpio_soc}, { .compatible = "nvidia,tegra194-gpio-aon", .data = &t194_aon_gpio_soc}, { }, }; static struct platform_driver tegra_gpio_driver = { .driver = { .name = "gpio-tegra186", .of_match_table = tegra_gpio_of_match, .pm = TEGRA_GPIO_PM, }, .probe = tegra_gpio_probe, }; static int __init tegra_gpio_init(void) { return platform_driver_register(&tegra_gpio_driver); } postcore_initcall(tegra_gpio_init); MODULE_AUTHOR("Suresh Mangipudi "); MODULE_AUTHOR("Laxman Dewangan "); MODULE_DESCRIPTION("NVIDIA Tegra186 GPIO driver"); MODULE_LICENSE("GPL v2");