Landfall

Annotated pkg/devices/keypad/src/qi_lb60/keypad-qi_lb60.cc

0:89a1bc19c1fc
2018-05-13 Paul Boddie Added device libraries and programs, configuration files and examples. Also added an installation script and copyright and licensing information.
paul@0 1
/*
paul@0 2
 * Export the keypad GPIOs on the Ben NanoNote as a data space accessible via
paul@0 3
 * the "keypad" capability.
paul@0 4
 *
paul@0 5
 * (c) 2018 Paul Boddie <paul@boddie.org.uk>
paul@0 6
 *
paul@0 7
 * This program is free software; you can redistribute it and/or
paul@0 8
 * modify it under the terms of the GNU General Public License as
paul@0 9
 * published by the Free Software Foundation; either version 2 of
paul@0 10
 * the License, or (at your option) any later version.
paul@0 11
 *
paul@0 12
 * This program is distributed in the hope that it will be useful,
paul@0 13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@0 14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@0 15
 * GNU General Public License for more details.
paul@0 16
 *
paul@0 17
 * You should have received a copy of the GNU General Public License
paul@0 18
 * along with this program; if not, write to the Free Software
paul@0 19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@0 20
 * Boston, MA  02110-1301, USA
paul@0 21
 */
paul@0 22
paul@0 23
#include <l4/devices/gpio-jz4740.h>
paul@0 24
#include <l4/devices/dataspace.h>
paul@0 25
#include <l4/devices/memory.h>
paul@0 26
#include "keypad-server.h"
paul@0 27
paul@0 28
#include <l4/sys/thread.h>
paul@0 29
#include <pthread.h>
paul@0 30
#include <pthread-l4.h>
paul@0 31
paul@0 32
#include <l4/re/dataspace>
paul@0 33
#include <l4/re/env>
paul@0 34
#include <l4/re/util/object_registry>
paul@0 35
paul@0 36
#include <l4/sys/cache.h>
paul@0 37
#include <l4/util/util.h>
paul@0 38
paul@0 39
#include <stdint.h>
paul@0 40
paul@0 41
enum Jz4740_keypad_gpio
paul@0 42
{
paul@0 43
  Jz4740_keypad_gpio_inputs_count = 8,
paul@0 44
  Jz4740_keypad_gpio_outputs_count = 8,
paul@0 45
};
paul@0 46
paul@0 47
/* Port D input pins. */
paul@0 48
paul@0 49
const uint8_t Jz4740_keypad_inputs[Jz4740_keypad_gpio_inputs_count] = {
paul@0 50
  18, 19, 20, 21, 22, 23, 24, 26
paul@0 51
};
paul@0 52
paul@0 53
const Pin_slice Jz4740_keypad_inputs_mask = {0x05fc0000, 0};
paul@0 54
paul@0 55
/* Port C output pins. */
paul@0 56
paul@0 57
const uint8_t Jz4740_keypad_outputs[Jz4740_keypad_gpio_outputs_count] = {
paul@0 58
  10, 11, 12, 13, 14, 15, 16, 17
paul@0 59
};
paul@0 60
paul@0 61
const Pin_slice Jz4740_keypad_outputs_mask = {0x0003fc00, 0};
paul@0 62
paul@0 63
/* Peripheral memory regions. */
paul@0 64
paul@0 65
static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0;
paul@0 66
paul@0 67
/* GPIO abstractions. */
paul@0 68
paul@0 69
static void *gpio_port_c, *gpio_port_d;
paul@0 70
paul@0 71
/* Keypad status: an array of keypad column values. */
paul@0 72
paul@0 73
uint32_t *keypad = 0;
paul@0 74
paul@0 75
/* Imported keypad memory referenced by the array. */
paul@0 76
paul@0 77
void *keymem = 0;
paul@0 78
paul@0 79
/* Thread details. */
paul@0 80
paul@0 81
static pthread_t _pthread;
paul@0 82
paul@0 83
paul@0 84
paul@0 85
/* Initialise the pins for scanning the keypad. */
paul@0 86
paul@0 87
static void init_keyscan(void)
paul@0 88
{
paul@0 89
  jz4740_gpio_multi_setup(gpio_port_d, &Jz4740_keypad_inputs_mask, Hw::Gpio_chip::Input, 0);
paul@0 90
  jz4740_gpio_multi_config_pull(gpio_port_d, &Jz4740_keypad_inputs_mask, Hw::Gpio_chip::Pull_up);
paul@0 91
  jz4740_gpio_multi_setup(gpio_port_c, &Jz4740_keypad_outputs_mask, Hw::Gpio_chip::Input, 0);
paul@0 92
}
paul@0 93
paul@0 94
/*
paul@0 95
Scan the keypad by enabling each output column and inspecting each input row.
paul@0 96
Store each column bitmap in the keypad array.
paul@0 97
*/
paul@0 98
paul@0 99
static void scan_keypad(void)
paul@0 100
{
paul@0 101
  uint8_t column, row, value;
paul@0 102
paul@0 103
  for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++)
paul@0 104
  {
paul@0 105
    jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Hw::Gpio_chip::Output, 0);
paul@0 106
    l4_sleep(1);
paul@0 107
paul@0 108
    value = 0;
paul@0 109
paul@0 110
    for (row = 0; row < Jz4740_keypad_gpio_inputs_count; row++)
paul@0 111
      value = (value << 1) | (jz4740_gpio_get(gpio_port_d, Jz4740_keypad_inputs[row]) ? 0 : 1);
paul@0 112
paul@0 113
    keypad[column] = value;
paul@0 114
paul@0 115
    jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Hw::Gpio_chip::Input, 0);
paul@0 116
  }
paul@0 117
paul@0 118
  l4_cache_clean_data((unsigned long) keypad,
paul@0 119
                      (unsigned long) keypad + Jz4740_keypad_gpio_outputs_count);
paul@0 120
}
paul@0 121
paul@0 122
/* Set up access to memory. */
paul@0 123
paul@0 124
static int setup_memory(void)
paul@0 125
{
paul@0 126
  if (get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end) < 0)
paul@0 127
    return 1;
paul@0 128
paul@0 129
  gpio_port_c = jz4740_gpio_init(gpio_virt_base + 0x200, gpio_virt_base + 0x300, 32);
paul@0 130
  gpio_port_d = jz4740_gpio_init(gpio_virt_base + 0x300, gpio_virt_base + 0x400, 32);
paul@0 131
paul@0 132
  return 0;
paul@0 133
}
paul@0 134
paul@0 135
paul@0 136
paul@0 137
/* Worker thread for scanning the keypad. */
paul@0 138
paul@0 139
static void *scan_thread(void *data)
paul@0 140
{
paul@0 141
  (void) data;
paul@0 142
paul@0 143
  while (1)
paul@0 144
  {
paul@0 145
    scan_keypad();
paul@0 146
    l4_sleep(20); /* 20ms -> 50Hz */
paul@0 147
  }
paul@0 148
paul@0 149
  return 0;
paul@0 150
}
paul@0 151
paul@0 152
/* Thread initialisation. */
paul@0 153
paul@0 154
static int init_thread(void)
paul@0 155
{
paul@0 156
  pthread_attr_t thread_attr;
paul@0 157
  struct sched_param sp;
paul@0 158
paul@0 159
  if (pthread_attr_init(&thread_attr))
paul@0 160
    return 1;
paul@0 161
paul@0 162
  sp.sched_priority = 0x20;
paul@0 163
  pthread_attr_setschedpolicy(&thread_attr, SCHED_L4);
paul@0 164
  pthread_attr_setschedparam(&thread_attr, &sp);
paul@0 165
  pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED);
paul@0 166
paul@0 167
  return pthread_create(&_pthread, &thread_attr, scan_thread, 0);
paul@0 168
}
paul@0 169
paul@0 170
paul@0 171
paul@0 172
static L4Re::Util::Registry_server<> server;
paul@0 173
paul@0 174
paul@0 175
paul@0 176
/* Main program. */
paul@0 177
paul@0 178
int main(void)
paul@0 179
{
paul@0 180
  /* Memory allocation capability for the keypad data. */
paul@0 181
paul@0 182
  L4::Cap<L4Re::Dataspace> mem;
paul@0 183
  l4_size_t mem_size = Jz4740_keypad_gpio_outputs_count * sizeof(uint32_t);
paul@0 184
paul@0 185
  if (setup_memory()) return 1;
paul@0 186
paul@0 187
  mem = allocate_data(mem_size, &keymem);
paul@0 188
paul@0 189
  if (!mem.is_valid()) return 1;
paul@0 190
paul@0 191
  keypad = (uint32_t *) keymem;
paul@0 192
paul@0 193
  /* Set up keypad access and start scanning. */
paul@0 194
paul@0 195
  init_keyscan();
paul@0 196
paul@0 197
  /* Set up a thread to scan the keypad concurrently with the server loop. */
paul@0 198
paul@0 199
  init_thread();
paul@0 200
paul@0 201
  /* Initialise and register a server object. */
paul@0 202
paul@0 203
  Keypad_server server_obj(mem);
paul@0 204
  server.registry()->register_obj(&server_obj, "keypad");
paul@0 205
paul@0 206
  /* Enter the IPC server loop. */
paul@0 207
paul@0 208
  server.loop();
paul@0 209
  return 0;
paul@0 210
}