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 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 "keypad-server.h" 27 #include "keypad-event-loop.h" 28 29 #include <l4/re/dataspace> 30 #include <l4/re/env> 31 #include <l4/re/util/object_registry> 32 33 #include <l4/sys/cache.h> 34 35 #include <stdint.h> 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 static L4Re::Util::Registry_server<> server; 132 133 134 135 /* Main program. */ 136 137 int main(void) 138 { 139 /* Memory allocation capability for the keypad data. */ 140 141 L4::Cap<L4Re::Dataspace> mem; 142 l4_size_t mem_size = Jz4740_keypad_gpio_outputs_count * sizeof(uint32_t); 143 144 if (setup_memory()) return 1; 145 146 mem = allocate_data(mem_size, &keymem); 147 148 if (!mem.is_valid()) return 1; 149 150 keypad = (uint32_t *) keymem; 151 152 /* Set up keypad access and start scanning. */ 153 154 init_keyscan(); 155 156 /* Set up a thread to scan the keypad concurrently with the server loop. */ 157 158 Keypad_event_loop loop; 159 loop.attach(scan_keypad); 160 loop.start(); 161 162 /* Initialise and register a server object. */ 163 164 Keypad_server server_obj(mem); 165 server.registry()->register_obj(&server_obj, "keypad"); 166 167 /* Enter the IPC server loop. */ 168 169 server.loop(); 170 return 0; 171 }