Landfall

pkg/landfall-examples/letux400_leds/letux400_leds.c

285:f09c2fffc7a8
6 months ago Paul Boddie Moved GPIO pull-up/down configurations into the GPIO library and simplified the GPIO initialisation interface. 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, 2024 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;   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   printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end);   150   printf("PORTA at 0x%lx...0x%lx.\n", gpio_base, gpio_base + 0x30);   151   printf("PORTC at 0x%lx...0x%lx.\n", gpio_base + 0x60, gpio_base + 0x90);   152    153   gpio_port_a = jz4730_gpio_init(gpio_base, 0);   154   gpio_port_c = jz4730_gpio_init(gpio_base, 2);   155    156   printf("Access PWM...\n");   157    158   if ((result = get_memory("jz4730-pwm", &pwm_base, &pwm_base_end)) < 0)   159     return 1;   160    161   pwm0_device = jz4730_pwm_init(pwm_base, pwm_base + 0x1000);   162    163   /* Set the GPIO pins up. */   164    165   printf("Set up GPIO pins...\n");   166    167   jz4730_gpio_setup(gpio_port_a, CAPS, Fix_output, caps);   168   jz4730_gpio_setup(gpio_port_c, NUM, Fix_output, num);   169   jz4730_gpio_config_pad(gpio_port_c, PWM, Function_alt, 1);   170    171   /* Set the PWM device up. */   172    173   printf("Set up PWM...\n");   174    175   jz4730_pwm_set_duty(pwm0_device, pwm);   176   jz4730_pwm_set_period(pwm0_device, 299);   177   jz4730_pwm_set_control(pwm0_device, 0x80 | 0x3f);   178    179   while (1)   180   {   181     caps = 1 - caps;   182     jz4730_gpio_set(gpio_port_a, CAPS, caps);   183     num = 1 - num;   184     jz4730_gpio_set(gpio_port_c, NUM, num);   185     pwm += pwmdir;   186     jz4730_pwm_set_duty(pwm0_device, pwm);   187     if (pwm == 0) pwmdir = 50; else if (pwm == 300) pwmdir = -50;   188     l4_sleep(1000); // 1000ms   189   }   190    191   return 0;   192 }