1 /* 2 * Export the keypad GPIOs on the Letux 400 as a data space accessible via the 3 * "keypad" capability. 4 * 5 * Copyright (C) 2018, 2023, 2024 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-jz4730.h> 24 #include <l4/devices/dataspace.h> 25 #include <l4/devices/memory.h> 26 27 #include <l4/re/c/dataspace.h> 28 #include <l4/re/env.h> 29 30 #include <l4/sys/cache.h> 31 32 #include <stdint.h> 33 34 #include "keypad-event-loop.h" 35 #include "keypad-run.h" 36 37 38 39 enum Jz4730_keypad_gpio 40 { 41 Jz4730_keypad_gpio_inputs_count = 8, 42 Jz4730_keypad_gpio_outputs_count = 17, 43 }; 44 45 /* Port A input pins. */ 46 47 const uint8_t Jz4730_keypad_inputs[Jz4730_keypad_gpio_inputs_count] = { 48 0, 1, 2, 3, 4, 5, 6, 7 49 }; 50 51 const Pin_slice Jz4730_keypad_inputs_mask = {0x000000ff, 0}; 52 53 /* Port D output pins. */ 54 55 const uint8_t Jz4730_keypad_outputs[Jz4730_keypad_gpio_outputs_count] = { 56 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 57 }; 58 59 const Pin_slice Jz4730_keypad_outputs_mask = {0x2000ffff, 0}; 60 61 /* Peripheral memory regions. */ 62 63 static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; 64 65 /* GPIO abstractions. */ 66 67 static void *gpio_port_a, *gpio_port_d; 68 69 /* Keypad status: an array of keypad column values. */ 70 71 uint32_t *keypad = 0; 72 73 /* Imported keypad memory referenced by the array. */ 74 75 void *keymem = 0; 76 77 78 79 /* Set up access to memory. */ 80 81 static int setup_memory() 82 { 83 if (get_memory("jz4730-gpio", &gpio_virt_base, &gpio_virt_base_end) < 0) 84 return 1; 85 86 gpio_port_a = jz4730_gpio_init(gpio_virt_base, 0); 87 gpio_port_d = jz4730_gpio_init(gpio_virt_base, 3); 88 89 return 0; 90 } 91 92 93 94 /* Initialise the pins for scanning the keypad. */ 95 96 static void init_keyscan() 97 { 98 jz4730_gpio_multi_setup(gpio_port_a, &Jz4730_keypad_inputs_mask, Hw::Gpio_chip::Input, 0); 99 jz4730_gpio_multi_config_pull(gpio_port_a, &Jz4730_keypad_inputs_mask, Hw::Gpio_chip::Pull_up); 100 jz4730_gpio_multi_setup(gpio_port_d, &Jz4730_keypad_outputs_mask, Hw::Gpio_chip::Input, 0); 101 } 102 103 /* 104 Scan the keypad by enabling each output column and inspecting each input row. 105 Store each column bitmap in the keypad array. 106 */ 107 108 static void scan_keypad() 109 { 110 uint8_t column, row, value; 111 112 for (column = 0; column < Jz4730_keypad_gpio_outputs_count; column++) 113 { 114 jz4730_gpio_setup(gpio_port_d, Jz4730_keypad_outputs[column], Hw::Gpio_chip::Output, 0); 115 l4_sleep(1); 116 117 value = 0; 118 119 for (row = 0; row < Jz4730_keypad_gpio_inputs_count; row++) 120 value = (value << 1) | (jz4730_gpio_get(gpio_port_a, Jz4730_keypad_inputs[row]) ? 0 : 1); 121 122 keypad[column] = value; 123 124 jz4730_gpio_setup(gpio_port_d, Jz4730_keypad_outputs[column], Hw::Gpio_chip::Input, 0); 125 } 126 127 l4_cache_clean_data((unsigned long) keypad, 128 (unsigned long) keypad + Jz4730_keypad_gpio_outputs_count); 129 } 130 131 132 133 /* Main program. */ 134 135 int main(void) 136 { 137 if (setup_memory()) 138 return 1; 139 140 /* Memory allocation capability for the keypad data. */ 141 142 l4_size_t mem_size = Jz4730_keypad_gpio_outputs_count * sizeof(uint32_t); 143 l4re_ds_t mem = allocate_data(mem_size, &keymem); 144 145 if (l4_is_invalid_cap(mem)) 146 return 1; 147 148 keypad = (uint32_t *) keymem; 149 150 /* Set up keypad access and start scanning. */ 151 152 init_keyscan(); 153 154 /* Set up a thread to scan the keypad concurrently with the server loop. */ 155 156 Keypad_event_loop loop; 157 loop.attach(scan_keypad); 158 loop.start(); 159 160 /* Start a server using the common server functionality. */ 161 162 return run(mem); 163 }