Landfall

Annotated pkg/landfall-examples/letux400_leds/letux400_leds.c

254:a437381bd5f4
9 months ago Paul Boddie Employed get_channel to eliminate redundant code. cpm-library-improvements
paul@0 1
/*
paul@0 2
 * Access the LED and PWM GPIOs on the Letux 400 notebook computer.
paul@0 3
 * This example shows how to use the following GPIOs:
paul@0 4
 *
paul@0 5
 * PA27 - Caps Lock
paul@0 6
 * PC22 - Num Lock
paul@0 7
 * PC30 - PWM backlight
paul@0 8
 *
paul@31 9
 * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
paul@0 10
 *
paul@0 11
 * This program is free software; you can redistribute it and/or
paul@0 12
 * modify it under the terms of the GNU General Public License as
paul@0 13
 * published by the Free Software Foundation; either version 2 of
paul@0 14
 * the License, or (at your option) any later version.
paul@0 15
 *
paul@0 16
 * This program is distributed in the hope that it will be useful,
paul@0 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@0 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@0 19
 * GNU General Public License for more details.
paul@0 20
 *
paul@0 21
 * You should have received a copy of the GNU General Public License
paul@0 22
 * along with this program; if not, write to the Free Software
paul@0 23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@0 24
 * Boston, MA  02110-1301, USA
paul@0 25
 */
paul@0 26
paul@0 27
#include <l4/devices/gpio-jz4730.h>
paul@0 28
#include <l4/devices/pwm-jz4730.h>
paul@0 29
paul@0 30
#include <l4/io/io.h>
paul@0 31
#include <l4/re/env.h>
paul@0 32
#include <l4/re/c/util/cap_alloc.h>
paul@0 33
#include <l4/sys/factory.h>
paul@0 34
#include <l4/sys/ipc.h>
paul@0 35
#include <l4/util/util.h>
paul@0 36
#include <l4/vbus/vbus.h>
paul@0 37
paul@0 38
#include <stdio.h>
paul@0 39
#include <stdint.h>
paul@0 40
#include <unistd.h>
paul@0 41
paul@0 42
enum {
paul@0 43
  CAPS = 27, // via PORTA
paul@0 44
  NUM = 22, // via PORTC
paul@0 45
  PWM = 30, // via PORTC
paul@0 46
};
paul@0 47
paul@0 48
paul@0 49
paul@0 50
/* Device and resource discovery. */
paul@0 51
paul@0 52
static char const *resource_type(enum l4io_resource_types_t type)
paul@0 53
{
paul@0 54
  switch (type)
paul@0 55
  {
paul@0 56
    case L4VBUS_RESOURCE_INVALID:
paul@0 57
    return "INVALID";
paul@0 58
paul@0 59
    case L4VBUS_RESOURCE_IRQ:
paul@0 60
    return "IRQ";
paul@0 61
paul@0 62
    case L4VBUS_RESOURCE_MEM:
paul@0 63
    return "MEMORY";
paul@0 64
paul@0 65
    default:
paul@0 66
    return "OTHER";
paul@0 67
  }
paul@0 68
}
paul@0 69
paul@0 70
static int get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh)
paul@0 71
{
paul@0 72
  int result = l4io_lookup_device(hid, dh, 0, rh);
paul@0 73
paul@0 74
  if (result < 0)
paul@0 75
    printf("Could not access '%s': %s\n", hid, result == -L4_ENOENT ? "no such device" : "no device");
paul@0 76
paul@0 77
  return result;
paul@0 78
}
paul@0 79
paul@0 80
static int get_resource(l4io_device_handle_t dh, l4io_resource_t *res,
paul@0 81
                             enum l4io_resource_types_t type)
paul@0 82
{
paul@0 83
  int current = 0, result = 0;
paul@0 84
  l4_cap_idx_t vbus = l4re_env_get_cap("vbus");
paul@0 85
paul@0 86
  do
paul@0 87
  {
paul@0 88
    result = l4vbus_get_resource(vbus, dh, current, res);
paul@0 89
paul@0 90
    if (result)
paul@0 91
      printf("Could not access resource of type %s.\n", resource_type(type));
paul@0 92
    else
paul@0 93
      printf("Resource %d: type %s, start=%lx, end=%lx\n", res->id,
paul@0 94
        resource_type(res->type), res->start, res->end);
paul@0 95
paul@0 96
    current++;
paul@0 97
  }
paul@0 98
  while ((!result) && (res->type != type));
paul@0 99
paul@0 100
  return result;
paul@0 101
}
paul@0 102
paul@0 103
static int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end)
paul@0 104
{
paul@0 105
  l4io_device_handle_t dh;
paul@0 106
  l4io_resource_handle_t rh;
paul@0 107
  l4io_resource_t res;
paul@0 108
  int result;
paul@0 109
paul@0 110
  result = get_device(hid, &dh, &rh);
paul@0 111
paul@0 112
  if (result < 0)
paul@0 113
    return result;
paul@0 114
paul@0 115
  result = get_resource(dh, &res, L4IO_RESOURCE_MEM);
paul@0 116
paul@0 117
  if (result)
paul@0 118
    return result;
paul@0 119
paul@0 120
  if ((result = l4io_request_iomem(res.start, res.end - res.start + 1,
paul@0 121
                                  L4IO_MEM_NONCACHED, start)))
paul@0 122
  {
paul@0 123
    printf("Could not get address for '%s'.\n", hid);
paul@0 124
    return result;
paul@0 125
  }
paul@0 126
paul@0 127
  printf("Resource at 0x%lx...0x%lx.\n", res.start, res.end);
paul@0 128
paul@0 129
  *end = *start + (res.end - res.start + 1);
paul@0 130
paul@0 131
  return 0;
paul@0 132
}
paul@0 133
paul@0 134
int main(void)
paul@0 135
{
paul@0 136
  l4_addr_t gpio_base = 0, gpio_base_end = 0, port_a, port_a_end, port_c, port_c_end;
paul@0 137
  l4_addr_t pwm_base = 0, pwm_base_end = 0;
paul@0 138
  void *gpio_port_a, *gpio_port_c, *pwm0_device;
paul@0 139
  int result = 0;
paul@0 140
  int caps = 0, num = 1, pwm = 300, pwmdir = -50;
paul@0 141
paul@0 142
  /* Obtain resource details describing the I/O memory. */
paul@0 143
paul@0 144
  printf("Access GPIO...\n");
paul@0 145
paul@0 146
  if ((result = get_memory("jz4730-gpio", &gpio_base, &gpio_base_end)) < 0)
paul@0 147
    return 1;
paul@0 148
paul@0 149
  port_a = gpio_base;
paul@0 150
  port_a_end = port_a + 0x30;
paul@0 151
  port_c = gpio_base + 0x60;
paul@0 152
  port_c_end = port_c + 0x30;
paul@0 153
paul@0 154
  printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end);
paul@0 155
  printf("PORTA at 0x%lx...0x%lx.\n", port_a, port_a_end);
paul@0 156
  printf("PORTC at 0x%lx...0x%lx.\n", port_c, port_c_end);
paul@0 157
paul@0 158
  gpio_port_a = jz4730_gpio_init(port_a, port_a_end, 32);
paul@0 159
  gpio_port_c = jz4730_gpio_init(port_c, port_c_end, 32);
paul@0 160
paul@0 161
  printf("Access PWM...\n");
paul@0 162
paul@0 163
  if ((result = get_memory("jz4730-pwm", &pwm_base, &pwm_base_end)) < 0)
paul@0 164
    return 1;
paul@0 165
paul@0 166
  pwm0_device = jz4730_pwm_init(pwm_base, pwm_base + 0x1000);
paul@0 167
paul@0 168
  /* Set the GPIO pins up. */
paul@0 169
paul@0 170
  printf("Set up GPIO pins...\n");
paul@0 171
paul@0 172
  jz4730_gpio_setup(gpio_port_a, CAPS, Fix_output, caps);
paul@0 173
  jz4730_gpio_setup(gpio_port_c, NUM, Fix_output, num);
paul@0 174
  jz4730_gpio_config_pad(gpio_port_c, PWM, Function_alt, 1);
paul@0 175
paul@0 176
  /* Set the PWM device up. */
paul@0 177
paul@0 178
  printf("Set up PWM...\n");
paul@0 179
paul@0 180
  jz4730_pwm_set_duty(pwm0_device, pwm);
paul@0 181
  jz4730_pwm_set_period(pwm0_device, 299);
paul@0 182
  jz4730_pwm_set_control(pwm0_device, 0x80 | 0x3f);
paul@0 183
paul@0 184
  while (1)
paul@0 185
  {
paul@0 186
    caps = 1 - caps;
paul@0 187
    jz4730_gpio_set(gpio_port_a, CAPS, caps);
paul@0 188
    num = 1 - num;
paul@0 189
    jz4730_gpio_set(gpio_port_c, NUM, num);
paul@0 190
    pwm += pwmdir;
paul@0 191
    jz4730_pwm_set_duty(pwm0_device, pwm);
paul@0 192
    if (pwm == 0) pwmdir = 50; else if (pwm == 300) pwmdir = -50;
paul@0 193
    l4_sleep(1000); // 1000ms
paul@0 194
  }
paul@0 195
paul@0 196
  return 0;
paul@0 197
}