Landfall

pkg/landfall-examples/letux400_leds/letux400_leds.c

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