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 }