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 <stdio.h> 28 #include <unistd.h> 29 #include <stdint.h> 30 31 #include "memory.h" 32 33 enum Jz4740_keypad_gpio 34 { 35 Jz4740_keypad_gpio_inputs_count = 8, 36 Jz4740_keypad_gpio_outputs_count = 8, 37 }; 38 39 /* Port D input pins. */ 40 41 const uint8_t Jz4740_keypad_inputs[Jz4740_keypad_gpio_inputs_count] = { 42 18, 19, 20, 21, 22, 23, 24, 26 43 }; 44 45 const Pin_slice Jz4740_keypad_inputs_mask = {.mask = 0x05fc0000, .offset = 0}; 46 47 /* Port C output pins. */ 48 49 const uint8_t Jz4740_keypad_outputs[Jz4740_keypad_gpio_outputs_count] = { 50 10, 11, 12, 13, 14, 15, 16, 17 51 }; 52 53 const Pin_slice Jz4740_keypad_outputs_mask = {.mask = 0x0003fc00, .offset = 0}; 54 55 /* Video abstractions. */ 56 57 static l4re_util_video_goos_fb_t gfb; 58 static l4re_video_view_info_t fbi; 59 static void *fb; 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_c, *gpio_port_d; 68 69 /* Keypad status. */ 70 71 uint8_t keypad[Jz4740_keypad_gpio_outputs_count]; 72 73 74 75 /* Initialise the pins for scanning the keypad. */ 76 77 static void init_keyscan(void) 78 { 79 jz4740_gpio_multi_setup(gpio_port_d, &Jz4740_keypad_inputs_mask, Fix_input, 0); 80 jz4740_gpio_multi_config_pull(gpio_port_d, &Jz4740_keypad_inputs_mask, Pull_up); 81 jz4740_gpio_multi_setup(gpio_port_c, &Jz4740_keypad_outputs_mask, Fix_input, 0); 82 } 83 84 /* 85 Scan the keypad by enabling each output column and inspecting each input row. 86 Store each column bitmap in the keypad array. 87 */ 88 89 static void scan_keypad(void) 90 { 91 uint8_t column, row, value; 92 93 for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++) 94 { 95 jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Fix_output, 0); 96 l4_sleep(1); 97 98 value = 0; 99 100 for (row = 0; row < Jz4740_keypad_gpio_inputs_count; row++) 101 value = (value << 1) | (jz4740_gpio_get(gpio_port_d, Jz4740_keypad_inputs[row]) ? 0 : 1); 102 103 keypad[column] = value; 104 105 jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Fix_input, 0); 106 } 107 } 108 109 static uint32_t bitmask(uint32_t size) 110 { 111 return (1 << size) - 1; 112 } 113 114 static uint32_t truncate_channel(uint32_t value, uint32_t size) 115 { 116 return (value >> (8 - size)) & bitmask(size); 117 } 118 119 static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) 120 { 121 if (bpp <= 8) *(uint8_t *) pos = value; 122 else if (bpp <= 16) *(uint16_t *) pos = value; 123 else *(uint32_t *) pos = value; 124 } 125 126 /* Show the state of a key on the display. */ 127 128 static void show_keystate(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) 129 { 130 uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); 131 uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; 132 uint32_t bytes_per_line = fbi.bytes_per_line; 133 uint32_t pos; 134 uint32_t col, row; 135 136 rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | 137 (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | 138 (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); 139 140 for (row = 0; row < h; row++) 141 { 142 pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; 143 144 for (col = 0; col < w; col++) 145 { 146 set_pixel(pos, bpp, rgb); 147 pos += bytes_per_pixel; 148 } 149 } 150 } 151 152 /* Show the keypad status on the display. */ 153 154 static void show_keypad(void) 155 { 156 uint32_t colsize = fbi.width / Jz4740_keypad_gpio_outputs_count, 157 rowsize = fbi.height / Jz4740_keypad_gpio_inputs_count; 158 uint8_t column, row; 159 uint32_t mask; 160 161 for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++) 162 163 for (row = 0, mask = 1 << (Jz4740_keypad_gpio_inputs_count - 1); 164 row < Jz4740_keypad_gpio_inputs_count; 165 row++, mask >>= 1) 166 167 show_keystate(column * colsize, row * rowsize, colsize, rowsize, 168 keypad[column] & mask ? 0xffffff : 0); 169 170 /* Refresh the display. */ 171 172 l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); 173 } 174 175 int main(void) 176 { 177 int result; 178 179 if ((result = get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end)) < 0) 180 return 1; 181 182 if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) 183 return 1; 184 185 if (l4re_util_video_goos_fb_view_info(&gfb, &fbi)) 186 return 1; 187 188 if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) 189 return 1; 190 191 gpio_port_c = jz4740_gpio_init(gpio_virt_base + 0x200, gpio_virt_base + 0x300, 32); 192 gpio_port_d = jz4740_gpio_init(gpio_virt_base + 0x300, gpio_virt_base + 0x400, 32); 193 194 init_keyscan(); 195 196 while (1) 197 { 198 scan_keypad(); 199 show_keypad(); 200 } 201 202 return 0; 203 }