1.1 --- a/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Wed Jul 24 00:54:00 2019 +0200
1.2 +++ b/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Sat Jan 25 16:07:18 2020 +0100
1.3 @@ -1,7 +1,7 @@
1.4 /*
1.5 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
1.6 * economic rights: Technische Universität Dresden (Germany)
1.7 - * Copyright (C) 2017, 2018, 2019 Paul Boddie <paul@boddie.org.uk>
1.8 + * Copyright (C) 2017, 2018, 2019, 2020 Paul Boddie <paul@boddie.org.uk>
1.9 *
1.10 * This file is part of TUD:OS and distributed under the terms of the
1.11 * GNU General Public License 2.
1.12 @@ -16,7 +16,6 @@
1.13 #include <l4/devices/i2c-jz4780.h>
1.14 #include <l4/devices/memory.h>
1.15 #include <l4/io/io.h>
1.16 -#include <l4/libedid/edid.h>
1.17 #include <l4/re/env.h>
1.18 #include <l4/re/c/util/cap_alloc.h>
1.19 #include <l4/sys/factory.h>
1.20 @@ -55,29 +54,6 @@
1.21 return start - index;
1.22 }
1.23
1.24 -static void show_deviceid(uint8_t buf[])
1.25 -{
1.26 - printf("Manufacturer %x part %x revision %x\n",
1.27 - (buf[0] << 4) | (buf[1] >> 4),
1.28 - ((buf[1] & 0xf) << 5) | (buf[2] >> 3),
1.29 - buf[2] & 0x7);
1.30 -}
1.31 -
1.32 -static void show_data(uint8_t buf[], unsigned pos)
1.33 -{
1.34 - unsigned i;
1.35 -
1.36 - if (pos)
1.37 - {
1.38 - printf("Read %d bytes from bus.\n", pos);
1.39 - for (i = 0; i < pos; i++)
1.40 - printf(" %02x", buf[i]);
1.41 - printf("\n");
1.42 - }
1.43 - else
1.44 - printf("No reply from bus.\n");
1.45 -}
1.46 -
1.47 static long i2c_read(void *i2c_channel, uint8_t *buf, unsigned length,
1.48 l4_cap_idx_t irqcap)
1.49 {
1.50 @@ -126,15 +102,34 @@
1.51 return jz4780_i2c_have_written(i2c_channel);
1.52 }
1.53
1.54 -static long i2c_get(void *i2c_channel, uint8_t reg, uint8_t *buffer, long length, l4_cap_idx_t irqcap)
1.55 +static long i2c_get(void *i2c_channel, uint8_t *buffer, long length, l4_cap_idx_t irqcap)
1.56 {
1.57 long pos;
1.58
1.59 + memset(buffer, 0, length);
1.60 + pos = i2c_read(i2c_channel, buffer, length, irqcap);
1.61 +
1.62 + jz4780_i2c_stop(i2c_channel);
1.63 +
1.64 + return pos;
1.65 +}
1.66 +
1.67 +static long i2c_get_reg(void *i2c_channel, uint8_t reg, uint8_t *buffer, long length, l4_cap_idx_t irqcap)
1.68 +{
1.69 buffer[0] = reg;
1.70 i2c_write(i2c_channel, buffer, 1, irqcap);
1.71
1.72 - memset(buffer, 0, length);
1.73 - pos = i2c_read(i2c_channel, buffer, length, irqcap);
1.74 + return i2c_get(i2c_channel, buffer, length, irqcap);
1.75 +}
1.76 +
1.77 +static long i2c_set_reg(void *i2c_channel, uint8_t reg, uint8_t *buffer, long length, l4_cap_idx_t irqcap)
1.78 +{
1.79 + uint8_t buf[length + 1];
1.80 + long pos;
1.81 +
1.82 + buf[0] = reg;
1.83 + memcpy(buf + 1, buffer, length);
1.84 + pos = i2c_write(i2c_channel, buf, length + 1, irqcap);
1.85
1.86 jz4780_i2c_stop(i2c_channel);
1.87
1.88 @@ -172,7 +167,7 @@
1.89 printf("\n");
1.90
1.91 jz4780_i2c_set_target(i2c_channel, address);
1.92 - i2c_get(i2c_channel, 0, buf, 1, irqcap);
1.93 + i2c_get(i2c_channel, buf, 1, irqcap);
1.94
1.95 if (!jz4780_i2c_failed(i2c_channel))
1.96 printf("%02x ", address);
1.97 @@ -186,82 +181,56 @@
1.98 printf("\n\n");
1.99 }
1.100
1.101 -static void ddc_read(void *i2c_channel, l4_cap_idx_t irqcap)
1.102 +static void pmic_dump(void *i2c_channel, l4_cap_idx_t irqcap)
1.103 {
1.104 - /* Buffer for reading. */
1.105 -
1.106 - uint8_t buf[128];
1.107 + uint8_t regs[] = {0x00, 0x01, 0x10, 0x12, 0x20, 0x22, 0x30, 0x32,
1.108 + 0x40, 0x41, 0x50, 0x51, 0x60, 0x61, 0x70, 0x71,
1.109 + 0x80, 0x81, 0x91};
1.110 + uint8_t buf[1];
1.111 long pos;
1.112 -
1.113 - /* DDC EDID details. */
1.114 -
1.115 - unsigned width = 0, height = 0;
1.116 -
1.117 - printf("Trying DDC on I2C4...\n");
1.118 -
1.119 - /* Attempt to read from address 0x50 for DDC.
1.120 - See: drivers/video/fbdev/core/fb_ddc.c */
1.121 + unsigned i;
1.122
1.123 - jz4780_i2c_set_target(i2c_channel, 0x50);
1.124 - pos = i2c_get(i2c_channel, 0, buf, 128, irqcap);
1.125 -
1.126 - if (pos <= 0)
1.127 + for (i = 0; i < sizeof(regs); i++)
1.128 {
1.129 - printf("Read failed.\n");
1.130 - return;
1.131 + printf("PMIC %02x:\n", regs[i]);
1.132 + jz4780_i2c_set_target(i2c_channel, 0x5a);
1.133 + pos = i2c_get_reg(i2c_channel, regs[i], buf, 1, irqcap);
1.134 + i2c_report(i2c_channel, buf, pos);
1.135 }
1.136 -
1.137 - show_data(buf, pos);
1.138 -
1.139 - /* Attempt to decode EDID information. */
1.140 -
1.141 - libedid_prefered_resolution(buf, &width, &height);
1.142 - printf("Preferred resolution: %d x %d\n", width, height);
1.143 -
1.144 - libedid_dump_standard_timings(buf);
1.145 }
1.146
1.147 -static void pmic_out3_control(void *i2c_channel, l4_cap_idx_t irqcap)
1.148 +static void rtc_dump(void *i2c_channel, l4_cap_idx_t irqcap, uint8_t *rtcregs)
1.149 {
1.150 - /* Buffer for communicating. */
1.151 -
1.152 - uint8_t buf[2];
1.153 -
1.154 - /* Attempt to read from address 0x5a for PMIC OUT3. */
1.155 -
1.156 - jz4780_i2c_set_target(i2c_channel, 0x5a);
1.157 - i2c_get(i2c_channel, 0x32, buf, 1, irqcap);
1.158 - i2c_report(i2c_channel, buf, 1);
1.159 -
1.160 -#if 0
1.161 - /* Disable the regulator. */
1.162 -
1.163 - printf("Updating...\n");
1.164 -
1.165 - buf[1] = buf[0] & ~0x80;
1.166 - buf[0] = 0x32;
1.167 - i2c_write(i2c_channel, buf, 2, irqcap);
1.168 - jz4780_i2c_stop(i2c_channel);
1.169 -
1.170 - /* Read back from the register. Seemed to give 0xff, which makes no real
1.171 - sense, although the regulator did bring the voltage level low. */
1.172 -
1.173 - i2c_get(i2c_channel, 0x32, buf, 1, irqcap);
1.174 - i2c_report(i2c_channel, buf, 1);
1.175 -#endif
1.176 -}
1.177 -
1.178 -static void rtc_control(void *i2c_channel, l4_cap_idx_t irqcap)
1.179 -{
1.180 - /* Buffer for communicating. */
1.181 -
1.182 - uint8_t buf[1];
1.183 -
1.184 /* Attempt to read from address 0x51 for RTC. */
1.185
1.186 jz4780_i2c_set_target(i2c_channel, 0x51);
1.187 - i2c_get(i2c_channel, 0x0f, buf, 1, irqcap);
1.188 - i2c_report(i2c_channel, buf, 1);
1.189 + i2c_get_reg(i2c_channel, 0x00, rtcregs, 16, irqcap);
1.190 + i2c_report(i2c_channel, rtcregs, 16);
1.191 +}
1.192 +
1.193 +static void rtc_datetime(uint8_t *rtcregs)
1.194 +{
1.195 + char *weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
1.196 + printf("%s %d%d-%d%d-%d%d %d%d:%d%d:%d%d\n",
1.197 + weekdays[rtcregs[0x06] & 0x07],
1.198 + (rtcregs[0x08] & 0xf0) >> 4,
1.199 + rtcregs[0x08] & 0x0f,
1.200 + (rtcregs[0x07] & 0x10) >> 4,
1.201 + rtcregs[0x07] & 0x0f,
1.202 + (rtcregs[0x05] & 0x30) >> 4,
1.203 + rtcregs[0x05] & 0x0f,
1.204 + (rtcregs[0x04] & 0x30) >> 4,
1.205 + rtcregs[0x04] & 0x0f,
1.206 + (rtcregs[0x03] & 0x70) >> 4,
1.207 + rtcregs[0x03] & 0x0f,
1.208 + (rtcregs[0x02] & 0x70) >> 4,
1.209 + rtcregs[0x02] & 0x0f);
1.210 +}
1.211 +
1.212 +static int rtc_update(void *i2c_channel, l4_cap_idx_t irqcap, uint8_t *rtcregs)
1.213 +{
1.214 + jz4780_i2c_set_target(i2c_channel, 0x51);
1.215 + return i2c_set_reg(i2c_channel, 0x02, rtcregs + 2, 7, irqcap);
1.216 }
1.217
1.218 int main(void)
1.219 @@ -275,11 +244,10 @@
1.220 l4_addr_t cpm_base = 0, cpm_base_end = 0;
1.221 l4_addr_t port_d, port_d_end;
1.222 l4_addr_t port_e, port_e_end;
1.223 - l4_addr_t port_f, port_f_end;
1.224
1.225 /* Peripheral abstractions. */
1.226
1.227 - void *gpio_port_d, *gpio_port_e, *gpio_port_f;
1.228 + void *gpio_port_d, *gpio_port_e;
1.229 void *i2c, *cpm;
1.230 void *i2c0, *i2c4;
1.231
1.232 @@ -288,6 +256,11 @@
1.233 l4_uint32_t i2c_irq_start = 0, i2c_irq_end = 0;
1.234 l4_cap_idx_t icucap, irq0cap, irq4cap;
1.235
1.236 + /* RTC registers. */
1.237 +
1.238 + uint8_t rtcregs[16];
1.239 + int i;
1.240 +
1.241 /* Obtain capabilities for the interrupt controller and an interrupt. */
1.242
1.243 irq0cap = l4re_util_cap_alloc();
1.244 @@ -381,27 +354,20 @@
1.245 port_d_end = port_d + 0x100;
1.246 port_e = gpio_base + 0x400;
1.247 port_e_end = port_e + 0x100;
1.248 - port_f = gpio_base + 0x500;
1.249 - port_f_end = port_f + 0x100;
1.250
1.251 printf("PORTD at 0x%lx...0x%lx.\n", port_d, port_d_end);
1.252 printf("PORTE at 0x%lx...0x%lx.\n", port_e, port_e_end);
1.253 - printf("PORTF at 0x%lx...0x%lx.\n", port_f, port_f_end);
1.254
1.255 gpio_port_d = jz4780_gpio_init(port_d, port_d_end, 32, 0xffff4fff, 0x0000b000);
1.256 gpio_port_e = jz4780_gpio_init(port_e, port_e_end, 32, 0xfffff37c, 0x00000483);
1.257 - gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0x7fa7f00f, 0x00580ff0);
1.258
1.259 printf("Set up GPIO pins...\n");
1.260
1.261 jz4780_gpio_config_pad(gpio_port_d, PMSCL, Function_alt, 0);
1.262 jz4780_gpio_config_pad(gpio_port_d, PMSDA, Function_alt, 0);
1.263
1.264 - //jz4780_gpio_config_pad(gpio_port_e, RTCSCL, Function_alt, 1);
1.265 - //jz4780_gpio_config_pad(gpio_port_e, RTCSDA, Function_alt, 1);
1.266 -
1.267 - jz4780_gpio_config_pad(gpio_port_f, DDCSCL, Function_alt, 1);
1.268 - jz4780_gpio_config_pad(gpio_port_f, DDCSDA, Function_alt, 1);
1.269 + jz4780_gpio_config_pad(gpio_port_e, RTCSCL, Function_alt, 1);
1.270 + jz4780_gpio_config_pad(gpio_port_e, RTCSDA, Function_alt, 1);
1.271
1.272 /* Obtain CPM and I2C objects. */
1.273
1.274 @@ -424,11 +390,28 @@
1.275 printf("Scan I2C4...\n");
1.276 i2c_scan(i2c4, irq4cap);
1.277
1.278 - pmic_out3_control(i2c0, irq0cap);
1.279 + printf("PMIC...\n");
1.280 + pmic_dump(i2c0, irq0cap);
1.281 +
1.282 + printf("RTC...\n");
1.283 + rtc_dump(i2c4, irq4cap, rtcregs);
1.284
1.285 - ddc_read(i2c4, irq4cap);
1.286 + rtcregs[0x02] = 0x56;
1.287 + rtcregs[0x03] = 0x34;
1.288 + rtcregs[0x04] = 0x12;
1.289 + rtcregs[0x05] = 0x25; /* 25th */
1.290 + rtcregs[0x06] = 0x06; /* Saturday */
1.291 + rtcregs[0x07] = 0x01; /* January */
1.292 + rtcregs[0x08] = 0x20; /* 2020 */
1.293
1.294 - //rtc_control(i2c4, irq4cap);
1.295 + printf("Updated %d registers.\n", rtc_update(i2c4, irq4cap, rtcregs));
1.296 +
1.297 + for (i = 0; i < 10; i++)
1.298 + {
1.299 + rtc_dump(i2c4, irq4cap, rtcregs);
1.300 + rtc_datetime(rtcregs);
1.301 + sleep(1);
1.302 + }
1.303
1.304 jz4780_i2c_disable(i2c0);
1.305 jz4780_i2c_disable(i2c4);