1 /* 2 * Access the keypad GPIOs on the Ben NanoNote. 3 * 4 * Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/devices/gpio-jz4740.h> 23 #include <l4/re/c/util/video/goos_fb.h> 24 #include <l4/re/c/video/view.h> 25 #include <l4/util/util.h> 26 27 #include <unistd.h> 28 #include <stdint.h> 29 30 #include "memory.h" 31 32 enum Jz4740_keypad_gpio 33 { 34 Jz4740_keypad_gpio_inputs_count = 8, 35 Jz4740_keypad_gpio_outputs_count = 8, 36 }; 37 38 /* Port D input pins. */ 39 40 const uint8_t Jz4740_keypad_inputs[Jz4740_keypad_gpio_inputs_count] = { 41 18, 19, 20, 21, 22, 23, 24, 26 42 }; 43 44 const Pin_slice Jz4740_keypad_inputs_mask = {.mask = 0x05fc0000, .offset = 0}; 45 46 /* Port C output pins. */ 47 48 const uint8_t Jz4740_keypad_outputs[Jz4740_keypad_gpio_outputs_count] = { 49 10, 11, 12, 13, 14, 15, 16, 17 50 }; 51 52 const Pin_slice Jz4740_keypad_outputs_mask = {.mask = 0x0003fc00, .offset = 0}; 53 54 /* Video abstractions. */ 55 56 static l4re_util_video_goos_fb_t gfb; 57 static l4re_video_view_info_t fbi; 58 static void *fb; 59 60 /* Peripheral memory regions. */ 61 62 static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; 63 64 /* GPIO abstractions. */ 65 66 static void *gpio_port_c, *gpio_port_d; 67 68 /* Keypad status. */ 69 70 uint8_t keypad[Jz4740_keypad_gpio_outputs_count]; 71 72 73 74 /* Initialise the pins for scanning the keypad. */ 75 76 static void init_keyscan(void) 77 { 78 jz4740_gpio_multi_setup(gpio_port_d, &Jz4740_keypad_inputs_mask, Fix_input, 0); 79 jz4740_gpio_multi_config_pull(gpio_port_d, &Jz4740_keypad_inputs_mask, Pull_up); 80 jz4740_gpio_multi_setup(gpio_port_c, &Jz4740_keypad_outputs_mask, Fix_input, 0); 81 } 82 83 /* 84 Scan the keypad by enabling each output column and inspecting each input row. 85 Store each column bitmap in the keypad array. 86 */ 87 88 static void scan_keypad(void) 89 { 90 uint8_t column, row, value; 91 92 for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++) 93 { 94 jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Fix_output, 0); 95 l4_sleep(1); 96 97 value = 0; 98 99 for (row = 0; row < Jz4740_keypad_gpio_inputs_count; row++) 100 value = (value << 1) | (jz4740_gpio_get(gpio_port_d, Jz4740_keypad_inputs[row]) ? 0 : 1); 101 102 keypad[column] = value; 103 104 jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Fix_input, 0); 105 } 106 } 107 108 static uint32_t bitmask(uint32_t size) 109 { 110 return (1 << size) - 1; 111 } 112 113 static uint32_t truncate_channel(uint32_t value, uint32_t size) 114 { 115 return (value >> (8 - size)) & bitmask(size); 116 } 117 118 static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) 119 { 120 if (bpp <= 8) *(uint8_t *) pos = value; 121 else if (bpp <= 16) *(uint16_t *) pos = value; 122 else *(uint32_t *) pos = value; 123 } 124 125 /* Show the state of a key on the display. */ 126 127 static void show_keystate(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) 128 { 129 uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); 130 uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; 131 uint32_t bytes_per_line = fbi.bytes_per_line; 132 uint32_t pos; 133 uint32_t col, row; 134 135 rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | 136 (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | 137 (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); 138 139 for (row = 0; row < h; row++) 140 { 141 pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; 142 143 for (col = 0; col < w; col++) 144 { 145 set_pixel(pos, bpp, rgb); 146 pos += bytes_per_pixel; 147 } 148 } 149 } 150 151 /* Show the keypad status on the display. */ 152 153 static void show_keypad(void) 154 { 155 uint32_t colsize = fbi.width / Jz4740_keypad_gpio_outputs_count, 156 rowsize = fbi.height / Jz4740_keypad_gpio_inputs_count; 157 uint8_t column, row; 158 uint32_t mask; 159 160 for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++) 161 162 for (row = 0, mask = 1 << (Jz4740_keypad_gpio_inputs_count - 1); 163 row < Jz4740_keypad_gpio_inputs_count; 164 row++, mask >>= 1) 165 166 show_keystate(column * colsize, row * rowsize, colsize, rowsize, 167 keypad[column] & mask ? 0xffffff : 0); 168 169 /* Refresh the display. */ 170 171 l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); 172 } 173 174 int main(void) 175 { 176 int result; 177 178 if ((result = get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end)) < 0) 179 return 1; 180 181 if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) 182 return 1; 183 184 if (l4re_util_video_goos_fb_view_info(&gfb, &fbi)) 185 return 1; 186 187 if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) 188 return 1; 189 190 gpio_port_c = jz4740_gpio_init(gpio_virt_base + 0x200, gpio_virt_base + 0x300, 32); 191 gpio_port_d = jz4740_gpio_init(gpio_virt_base + 0x300, gpio_virt_base + 0x400, 32); 192 193 init_keyscan(); 194 195 while (1) 196 { 197 scan_keypad(); 198 show_keypad(); 199 } 200 201 return 0; 202 }