1 /* 2 * Export the keypad GPIOs on the Ben NanoNote as a data space accessible via 3 * the "keypad" capability. 4 * 5 * Copyright (C) 2018, 2023 Paul Boddie <paul@boddie.org.uk> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA 21 */ 22 23 #include <l4/devices/gpio-jz4740.h> 24 #include <l4/devices/dataspace.h> 25 #include <l4/devices/memory.h> 26 #include <l4/re/c/dataspace.h> 27 #include <l4/re/env.h> 28 #include <l4/sys/cache.h> 29 30 #include <stdint.h> 31 32 #include "keypad-event-loop.h" 33 #include "keypad-run.h" 34 35 36 37 enum Jz4740_keypad_gpio 38 { 39 Jz4740_keypad_gpio_inputs_count = 8, 40 Jz4740_keypad_gpio_outputs_count = 8, 41 }; 42 43 /* Port D input pins. */ 44 45 const uint8_t Jz4740_keypad_inputs[Jz4740_keypad_gpio_inputs_count] = { 46 18, 19, 20, 21, 22, 23, 24, 26 47 }; 48 49 const Pin_slice Jz4740_keypad_inputs_mask = {0x05fc0000, 0}; 50 51 /* Port C output pins. */ 52 53 const uint8_t Jz4740_keypad_outputs[Jz4740_keypad_gpio_outputs_count] = { 54 10, 11, 12, 13, 14, 15, 16, 17 55 }; 56 57 const Pin_slice Jz4740_keypad_outputs_mask = {0x0003fc00, 0}; 58 59 /* Peripheral memory regions. */ 60 61 static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; 62 63 /* GPIO abstractions. */ 64 65 static void *gpio_port_c, *gpio_port_d; 66 67 /* Keypad status: an array of keypad column values. */ 68 69 uint32_t *keypad = 0; 70 71 /* Imported keypad memory referenced by the array. */ 72 73 void *keymem = 0; 74 75 76 77 /* Set up access to memory. */ 78 79 static int setup_memory() 80 { 81 if (get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end) < 0) 82 return 1; 83 84 gpio_port_c = jz4740_gpio_init(gpio_virt_base + 0x200, gpio_virt_base + 0x300, 32); 85 gpio_port_d = jz4740_gpio_init(gpio_virt_base + 0x300, gpio_virt_base + 0x400, 32); 86 87 return 0; 88 } 89 90 91 92 /* Initialise the pins for scanning the keypad. */ 93 94 static void init_keyscan() 95 { 96 jz4740_gpio_multi_setup(gpio_port_d, &Jz4740_keypad_inputs_mask, Hw::Gpio_chip::Input, 0); 97 jz4740_gpio_multi_config_pull(gpio_port_d, &Jz4740_keypad_inputs_mask, Hw::Gpio_chip::Pull_up); 98 jz4740_gpio_multi_setup(gpio_port_c, &Jz4740_keypad_outputs_mask, Hw::Gpio_chip::Input, 0); 99 } 100 101 /* 102 Scan the keypad by enabling each output column and inspecting each input row. 103 Store each column bitmap in the keypad array. 104 */ 105 106 static void scan_keypad() 107 { 108 uint8_t column, row, value; 109 110 for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++) 111 { 112 jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Hw::Gpio_chip::Output, 0); 113 l4_sleep(1); 114 115 value = 0; 116 117 for (row = 0; row < Jz4740_keypad_gpio_inputs_count; row++) 118 value = (value << 1) | (jz4740_gpio_get(gpio_port_d, Jz4740_keypad_inputs[row]) ? 0 : 1); 119 120 keypad[column] = value; 121 122 jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Hw::Gpio_chip::Input, 0); 123 } 124 125 l4_cache_clean_data((unsigned long) keypad, 126 (unsigned long) keypad + Jz4740_keypad_gpio_outputs_count); 127 } 128 129 130 131 /* Main program. */ 132 133 int main(void) 134 { 135 if (setup_memory()) 136 return 1; 137 138 /* Memory allocation capability for the keypad data. */ 139 140 l4_size_t mem_size = Jz4740_keypad_gpio_outputs_count * sizeof(uint32_t); 141 l4re_ds_t mem = allocate_data(mem_size, &keymem); 142 143 if (l4_is_invalid_cap(mem)) 144 return 1; 145 146 keypad = (uint32_t *) keymem; 147 148 /* Set up keypad access and start scanning. */ 149 150 init_keyscan(); 151 152 /* Set up a thread to scan the keypad concurrently with the server loop. */ 153 154 Keypad_event_loop loop; 155 loop.attach(scan_keypad); 156 loop.start(); 157 158 /* Start a server using the common server functionality. */ 159 160 return run(mem); 161 }